1 Plan that I wrote with Richi’s comments

Link at https://docs.google.com/document/d/1bdNeOMAYY90k8FAbPRWGBgS1YBEdP09kP0vcW0tNgPc/edit?usp=sharing

Package version inconsistency detected.
TMB was built with Matrix version 1.2.15
Current Matrix version is 1.2.17
Please re-install 'TMB' from source using install.packages('TMB', type = 'source') or ask CRAN for a binary version of 'TMB' matching CRAN's 'Matrix' package

2 Read in data

european <- read_csv("01-cleaning_data_data/european_recoded.csv")
australian <- read_csv("01-cleaning_data_data/australian_recoded.csv")
dim(european)
[1] 209 117
dim(australian)
[1] 269 146
european$EU <- 1
australian$AU <- 1
all <- merge(european,australian,all = TRUE)
table(all$EU,all$AU,useNA = "always")
      
         1 <NA>
  1      0  209
  <NA> 269    0

2.1 Variables to describe dataset (can be different between contexts)

demographics_var <- c("Age","Gender","L1","speak.other.L2","study.other.L2","origins","year.studyL2","other5.other.ways","degree","roleL2.degree","study.year","prof","L2.VCE","uni1.year","Context")
l2School <- "\\.L2school$"
l2School_variables <- colnames(all)[grep(l2School,colnames(all))]
  • First language
#table(all$L1,all$Context) # too many levels - needs to be cleaned (ex tot number of languages?)
table(all$L1,useNA = "always")

         Afrikaans           Albanian            Burmese 
                 1                  2                  1 
         Cantonese            Chinese           Croatian 
                 4                  7                  1 
             Dutch            English  English and Dutch 
                 1                201                  2 
            German German and English German and Turkish 
                77                  2                  1 
                 I         Indonesian            Italian 
                 1                  1                 89 
          Japanese           Mandarin            Persian 
                 1                  5                  1 
   Persian (Farsi)           Romanian            Russian 
                 1                  3                  2 
            Sindhi             Slovak            Spanish 
                 1                  1                  3 
           Turkish          Ukrainian               <NA> 
                 1                  1                 67 
ggplot(all,aes(x=L1,fill=Context)) + geom_bar() + coord_flip() + ggtitle("First Language") + labs(y="N. of participants",x="")+theme_bw()

#table(all$speak.other.L2,all$Context)
L2 <- data.frame(Freq=table(all$speak.other.L2)[order(table(all$speak.other.L2),decreasing = TRUE)],
                 L2=names(table(all$speak.other.L2))[order(table(all$speak.other.L2),decreasing = TRUE)]) # too many levels - needs to be cleaned (ex tot number of languages?)
head(L2)
  • origins
table(all$origins,useNA = "always")

  No  Yes <NA> 
 323   89   66 
table(all$year.studyL2)

                     0 years                   1- 3 years 
                          69                           12 
                   1-3 years                    4-6 years 
                          11                           61 
First year of primary school                 Kindergarten 
                          80                           30 
            Less than a year            more than 6 years 
                          27                           49 
                       Other 
                          72 
table(all$degree)

                    BA in Anglistik 
                                 43 
           BA in Nordamerikastudien 
                                  4 
                                HUM 
                                129 
                            HUM.SCI 
                                  6 
                                 LA 
                                 36 
     Lingue e letterature straniere 
                                 82 
Lingue, mercati e culture dell'Asia 
                                 13 
                                 QC 
                                  5 
                                SCI 
                                 86 
  • study.year in the European context is uni1.year in the Australian context
all$study.year[is.na(all$study.year)] <- all$uni1.year[is.na(all$study.year)]
#table(all$study.year)
all$study.year <- ifelse(all$study.year == "Already graduated after 5 semesters in March 2016, was interested in survery/study, sorry.","6th semester",all$study.year)
table(all$study.year)

      1st semester           1st year       2nd semester 
                72                255                  5 
          2nd year       3rd semester           3rd year 
                37                  5                 20 
3rd year of Master  4th year bachelor       5th semester 
                 1                  8                  2 
      6th semester           7th year             Master 
                 3                  1                  3 
  • proficiency
table(all$prof,useNA = "always")

          Advanced         Elementary       Intermediate 
                78                105                 84 
Upper-intermediate               <NA> 
               146                 65 

3 Filter participants : keep only the ones that meet the inclusion criteria

all$study.year[is.na(all$study.year)] <- all$uni1.year[is.na(all$study.year)]
# Filter only subject that we want to include in the study
# names(table(all$study.year))[1] = 1st semester"
filtered <- subset(all, (study.year == "1st year") | (study.year == names(table(all$study.year))[1]))
#& year.studyL2 != "0 years"

3.1 Imputing degree based on Quality Comments provided in the questions

  • 5313976716 : SCI (wish to study science in the future)
  • 5359866545 : HUM.SCI (based on degree.other7)
  • 5375370122 : SCI (she wants to do science)
  • 5375376761 : HUM (she wants to do translation/reserach/teaching)
filtered$degree[filtered$Resp.ID %in% "5313976716"] <- "SCI"
filtered$degree[filtered$Resp.ID %in% "5359866545"] <- "HUM.SCI"
filtered$degree[filtered$Resp.ID %in% "5375370122"] <- "SCI"
filtered$degree[filtered$Resp.ID %in% "5375376761"] <- "HUM"
table(filtered$degree)

                    BA in Anglistik 
                                 39 
           BA in Nordamerikastudien 
                                  4 
                                HUM 
                                 98 
                            HUM.SCI 
                                  6 
                                 LA 
                                 27 
     Lingue e letterature straniere 
                                 78 
Lingue, mercati e culture dell'Asia 
                                 13 
                                SCI 
                                 58 
kable(table(filtered$Context))

Var1 Freq
English in Germany 72
English in Italy 91
German in Australia 89
Italian in Australia 75

kable(table(filtered$year.studyL2,filtered$Context))

English in Germany English in Italy German in Australia Italian in Australia
0 years 0 0 22 11
1- 3 years 0 0 0 9
1-3 years 0 0 7 0
4-6 years 0 0 35 20
First year of primary school 17 56 0 0
Kindergarten 6 23 0 0
Less than a year 0 0 13 5
more than 6 years 0 0 11 30
Other 48 12 0 0

kable(table(filtered$year.studyL2,filtered$prof))

Advanced Elementary Intermediate Upper-intermediate
0 years 0 32 1 0
1- 3 years 0 4 5 0
1-3 years 0 1 3 3
4-6 years 1 9 26 19
First year of primary school 20 1 6 46
Kindergarten 8 1 3 17
Less than a year 0 11 4 3
more than 6 years 2 5 16 18
Other 33 0 5 22

kable(table(filtered$year.studyL2,filtered$Context))
English in Germany English in Italy German in Australia Italian in Australia
0 years 0 0 22 11
1- 3 years 0 0 0 9
1-3 years 0 0 7 0
4-6 years 0 0 35 20
First year of primary school 17 56 0 0
Kindergarten 6 23 0 0
Less than a year 0 0 13 5
more than 6 years 0 0 11 30
Other 48 12 0 0

People that have studied 0 years L2 are just a small subset of the German in Australia and Italian in Australia context which means that by correcting for context we are not removing the effect of the 0 years. A way to remove the effect of the 0 years participants and not including too many variables could be to estimate the effect of 0 years vs all.

4 Define demographic variables

4.1 Need to check datasets with Rcihi (why do we have QC in L1? Am I using not the latest dataset?)

all <- filtered
demographics_var <- c("Age","Gender","L1","speak.other.L2","study.other.L2","origins","year.studyL2","other5.other.ways","degree","roleL2.degree","study.year","prof","L2.VCE","uni1.year","Context")
l2School <- "\\.L2school$"
l2School_variables <- colnames(all)[grep(l2School,colnames(all))]
ggplot(all,aes(x=L1,fill=Context)) + geom_bar() + coord_flip() + ggtitle("First Language") + labs(y="N. of participants",x="") + theme_bw()

table(all$L1,all$Context)
                    
                     English in Germany English in Italy
  Afrikaans                           0                0
  Albanian                            0                1
  Cantonese                           0                0
  Chinese                             0                2
  Dutch                               1                0
  English                             1                0
  English and Dutch                   0                0
  German                             64                0
  German and English                  1                0
  I                                   0                0
  Indonesian                          0                0
  Italian                             0               87
  Japanese                            0                0
  Mandarin                            0                0
  Persian (Farsi)                     0                0
  Romanian                            0                0
  Russian                             2                0
  Sindhi                              0                0
  Spanish                             1                0
  Turkish                             1                0
  Ukrainian                           0                1
                    
                     German in Australia Italian in Australia
  Afrikaans                            1                    0
  Albanian                             0                    0
  Cantonese                            2                    0
  Chinese                              2                    0
  Dutch                                0                    0
  English                             75                   73
  English and Dutch                    2                    0
  German                               0                    0
  German and English                   1                    0
  I                                    0                    1
  Indonesian                           1                    0
  Italian                              0                    0
  Japanese                             1                    0
  Mandarin                             1                    1
  Persian (Farsi)                      1                    0
  Romanian                             1                    0
  Russian                              0                    0
  Sindhi                               1                    0
  Spanish                              0                    0
  Turkish                              0                    0
  Ukrainian                            0                    0
table(all$degree,all$L1)
                                     
                                      Afrikaans Albanian
  BA in Anglistik                             0        0
  BA in Nordamerikastudien                    0        0
  HUM                                         1        0
  HUM.SCI                                     0        0
  LA                                          0        0
  Lingue e letterature straniere              0        1
  Lingue, mercati e culture dell'Asia         0        0
  SCI                                         0        0
                                     
                                      Cantonese Chinese Dutch
  BA in Anglistik                             0       0     0
  BA in Nordamerikastudien                    0       0     0
  HUM                                         2       0     0
  HUM.SCI                                     0       0     0
  LA                                          0       0     1
  Lingue e letterature straniere              0       1     0
  Lingue, mercati e culture dell'Asia         0       1     0
  SCI                                         0       2     0
                                     
                                      English English and Dutch
  BA in Anglistik                           1                 0
  BA in Nordamerikastudien                  0                 0
  HUM                                      93                 1
  HUM.SCI                                   6                 0
  LA                                        0                 0
  Lingue e letterature straniere            0                 0
  Lingue, mercati e culture dell'Asia       0                 0
  SCI                                      47                 1
                                     
                                      German German and English
  BA in Anglistik                         34                  1
  BA in Nordamerikastudien                 4                  0
  HUM                                      0                  0
  HUM.SCI                                  0                  0
  LA                                      25                  0
  Lingue e letterature straniere           0                  0
  Lingue, mercati e culture dell'Asia      0                  0
  SCI                                      0                  1
                                     
                                       I Indonesian Italian
  BA in Anglistik                      0          0       0
  BA in Nordamerikastudien             0          0       0
  HUM                                  1          0       0
  HUM.SCI                              0          0       0
  LA                                   0          0       0
  Lingue e letterature straniere       0          0      75
  Lingue, mercati e culture dell'Asia  0          0      12
  SCI                                  0          1       0
                                     
                                      Japanese Mandarin
  BA in Anglistik                            0        0
  BA in Nordamerikastudien                   0        0
  HUM                                        0        0
  HUM.SCI                                    0        0
  LA                                         0        0
  Lingue e letterature straniere             0        0
  Lingue, mercati e culture dell'Asia        0        0
  SCI                                        1        2
                                     
                                      Persian (Farsi) Romanian
  BA in Anglistik                                   0        0
  BA in Nordamerikastudien                          0        0
  HUM                                               0        0
  HUM.SCI                                           0        0
  LA                                                0        0
  Lingue e letterature straniere                    0        0
  Lingue, mercati e culture dell'Asia               0        0
  SCI                                               1        1
                                     
                                      Russian Sindhi Spanish
  BA in Anglistik                           2      0       1
  BA in Nordamerikastudien                  0      0       0
  HUM                                       0      0       0
  HUM.SCI                                   0      0       0
  LA                                        0      0       0
  Lingue e letterature straniere            0      0       0
  Lingue, mercati e culture dell'Asia       0      0       0
  SCI                                       0      1       0
                                     
                                      Turkish Ukrainian
  BA in Anglistik                           0         0
  BA in Nordamerikastudien                  0         0
  HUM                                       0         0
  HUM.SCI                                   0         0
  LA                                        1         0
  Lingue e letterature straniere            0         1
  Lingue, mercati e culture dell'Asia       0         0
  SCI                                       0         0
  • Check for L1 but we decided not to filter for it
#Filter by L1
nc <- names(table(all$Context))
table(all$Context)

  English in Germany     English in Italy  German in Australia 
                  72                   91                   89 
Italian in Australia 
                  75 
l1_filter <- all[(all$Context == nc[1] & (all$L1 == "German" | all$L1 == "German and English")) | 
                    (all$Context == nc[2] & (all$L1 == "Italian")) | 
                    (all$Context == nc[3] & (all$L1 == "English" | all$L1 == "English and Dutch" | all$L1 == "German and English")) |
                    (all$Context == nc[4] & (all$L1 == "English" | all$L1 == "English and Dutch" | all$L1 == "German and English")),]
#all <- l1_filter
# do not filter for L1
all <- all
# subset demographics
demo <- subset(all,select=c("Resp.ID",demographics_var,l2School_variables))
# Numeri finali
table(l1_filter$Context)

  English in Germany     English in Italy  German in Australia 
                  65                   87                   78 
Italian in Australia 
                  73 
table(all$Context)

  English in Germany     English in Italy  German in Australia 
                  72                   91                   89 
Italian in Australia 
                  75 
  • Filter missing value:
  • Filter participants who didn’t put the degree
  • we don’t care about speak.other.L2 and study.other.L2
missing_bySample <- rowSums(is.na(demo))
names(missing_bySample) <- demo$Resp.ID
missing_byVar <- colSums(is.na(demo))
names(missing_byVar) <- colnames(demo)
barplot(missing_bySample)

d <- data.frame(miss=missing_byVar)
d$varID <- rownames(d)
ggplot(data=d,aes(x=varID,y=miss)) + geom_bar(stat="identity") + theme_bw() +theme(axis.text.x = element_text(angle = 45, hjust = 1)) 

demo_missing <- demo %>% group_by(Context) %>% summarise(roleL2.degree_na = sum(is.na(roleL2.degree)),
                                                         L2.VCE_na = sum(is.na(L2.VCE)),
                                                         other5.other.ways_na=sum(is.na(other5.other.ways )),
                                                         uni1.year_na = sum(is.na(uni1.year)),
                                                         primary1.L2school_na=sum(is.na(primary1.L2school)),
                                                         CLS3.L2school_na = sum(is.na(CLS3.L2school)),
                                                         VSL4.L2school_na=sum(is.na(VSL4.L2school)),
                                                         degree = sum(is.na(degree)),
                                                         schooL2country5.L2school_na=sum(is.na(schooL2country5.L2school)))
# We do not filter for speak.other.L2 or study.other.L2
#demo[is.na(demo$speak.other.L2),]
# teniamo
#demo[is.na(demo$study.other.L2),]
missing_bySample[names(missing_bySample) == "5166861581"]
5166861581 
        10 
#demo[is.na(demo$year.studyL2),]
missing_bySample[names(missing_bySample) == "5378798787"]
5378798787 
         3 
# remove NA from degree
#table(demo$degree,useNA = "always")
# Remove people
all <- all[!is.na(all$degree),]

4.2 Stats about filtered dataset

kable(table(all$Context))

Var1 Freq
English in Germany 70
English in Italy 91
German in Australia 88
Italian in Australia 74

kable(table(all$study.year))

Var1 Freq
1st semester 70
1st year 253

kable(table(all$year.studyL2))
Var1 Freq
0 years 33
1- 3 years 9
1-3 years 7
4-6 years 53
First year of primary school 73
Kindergarten 29
Less than a year 18
more than 6 years 41
Other 59

4.3 Recoded demographic variables

recoded_dem_richi <- read_excel("02-descriptive_data/21 03 merged_filtered_imputedMedian_likertNumber.xlsx")

-
/
                                                                

4.4 Write filtered and merged dataset

write.csv(all,file.path("02-descriptive_data/context-merged_filtered.csv"))

4.5 Descriptive plots and tables

all$speak.other.L2_binary <- ifelse(!is.na(all$speak.other.L2) & 
                                      !(all$speak.other.L2 %in% c("Yes","No")),"Yes",as.character(all$speak.other.L2))
kable(table(all$speak.other.L2_binary,all$Context,useNA = "always"))
English in Germany English in Italy German in Australia Italian in Australia NA
No 12 24 52 53 0
Yes 57 67 36 20 0
NA 1 0 0 1 0
  • Age
tabAge <- t(table(all$Age,all$Context))
ggdf <- data.frame(Age = rep(colnames(tabAge),each=4)[!(as.numeric(tabAge) == 0)],
  N.Participants = as.numeric(tabAge)[!(as.numeric(tabAge) == 0)],
  Context = rep(rownames(tabAge),times=3)[!(as.numeric(tabAge) == 0)])
ggplot(ggdf,aes(x=Age,y=N.Participants,fill=Context)) + geom_bar(position="dodge",colour="white",stat="identity")  + scale_y_continuous(breaks=seq(0,90,10),limits=c(0,90)) + theme_bw() + ggtitle("Participants by age")+
  geom_text(aes(label = N.Participants), hjust=0.5, vjust=-0.25, size = 2.5,position=position_dodge(width=0.9)) 

# add numbers on the bar
tabAge <- t(table(all$Gender,all$Context))
ggdf <- data.frame(Gender = rep(colnames(tabAge),each=4)[!(as.numeric(tabAge) == 0)],
  N.Participants = as.numeric(tabAge)[!(as.numeric(tabAge) == 0)],
  Context = rep(rownames(tabAge),times=3)[!(as.numeric(tabAge) == 0)])
ggplot(ggdf,aes(x=Gender,y=N.Participants,fill=Context)) + geom_bar(position="dodge",colour="white",stat="identity")  + labs(y="N participants") + scale_y_continuous(breaks=seq(0,90,10),limits=c(0,90)) + theme_bw() + ggtitle("Participants by gender")+  geom_text(aes(label = N.Participants), hjust=0.5, vjust=-0.25, size = 2.5,position=position_dodge(width=0.9)) 

# add numbers on the bar
tabAge <- t(table(all$origins,all$Context))
ggplot(all,aes(x=origins,fill=Context)) + geom_bar(position="dodge",colour="white") + ggtitle("Origins by context") + scale_y_continuous(breaks=seq(0,90,10),limits=c(0,90)) + theme_bw() + draw_grob(tableGrob(tabAge), x=2, y=60, width=0.3, height=0.4) + ggtitle("Participants by origins")

tabAge
                      
                       No Yes
  English in Germany   65   5
  English in Italy     90   1
  German in Australia  63  25
  Italian in Australia 36  38
  • proficiency
tabAge <- t(table(all$prof,all$Context))
ggplot(all,aes(x=Context,fill=prof)) + geom_bar(position="dodge",colour="white") + ggtitle("Proficiency by context") + scale_y_continuous(breaks=seq(0,90,10),limits=c(0,90)) + theme_bw() + draw_grob(tableGrob(tabAge), x=2, y=80, width=0.3, height=0.4)

tabAge
                      
                       Advanced Elementary Intermediate
  English in Germany         38          0            5
  English in Italy           23          2            9
  German in Australia         4         32           25
  Italian in Australia        0         29           29
                      
                       Upper-intermediate
  English in Germany                   27
  English in Italy                     57
  German in Australia                  27
  Italian in Australia                 16
  • L2.VCE
tabAge <- t(table(all[all$Context != "English in Germany" & all$Context != "English in Italy","L2.VCE"],all[all$Context != "English in Germany" & all$Context != "English in Italy",'Context'],useNA = "always"))
tabAge <- tabAge[-3,]
ggplot(all[all$Context != "English in Germany" & all$Context != "English in Italy",],aes(x=Context,fill=L2.VCE)) + geom_bar(position="dodge",colour="white") + ggtitle("L2.VCE by context") + scale_y_continuous(breaks=seq(0,90,10),limits=c(0,90)) + theme_bw() + draw_grob(tableGrob(tabAge), x=2, y=80, width=0.3, height=0.4)

  • da mettere a posto con Richi
# year study L2
table(all$year.studyL2,all$other.year.studyL2.richi)
                              
                               BILINGUAL FIRST.YEAR.SECONDARY
  0 years                              0                    0
  1- 3 years                           0                    0
  1-3 years                            0                    0
  4-6 years                            0                    0
  First year of primary school         0                    0
  Kindergarten                         0                    0
  Less than a year                     0                    0
  more than 6 years                    0                    0
  Other                                4                   10
                              
                               FOURTH.YEAR.PRIMARY
  0 years                                        0
  1- 3 years                                     0
  1-3 years                                      0
  4-6 years                                      0
  First year of primary school                   0
  Kindergarten                                   0
  Less than a year                               0
  more than 6 years                              0
  Other                                          5
                              
                               LOWER.SECONDARY PERSONAL
  0 years                                    0        0
  1- 3 years                                 0        0
  1-3 years                                  0        0
  4-6 years                                  0        0
  First year of primary school               0        0
  Kindergarten                               0        0
  Less than a year                           0        0
  more than 6 years                          0        0
  Other                                      4        2
                              
                               SECOND.YEAR.PRIMARY
  0 years                                        0
  1- 3 years                                     0
  1-3 years                                      0
  4-6 years                                      0
  First year of primary school                   0
  Kindergarten                                   0
  Less than a year                               0
  more than 6 years                              0
  Other                                          2
                              
                               SECOND.YEAR.SECONDARY
  0 years                                          0
  1- 3 years                                       0
  1-3 years                                        0
  4-6 years                                        0
  First year of primary school                     0
  Kindergarten                                     0
  Less than a year                                 0
  more than 6 years                                0
  Other                                            2
                              
                               THIRD.YEAR.PRIMARY
  0 years                                       0
  1- 3 years                                    0
  1-3 years                                     0
  4-6 years                                     0
  First year of primary school                  0
  Kindergarten                                  0
  Less than a year                              0
  more than 6 years                             0
  Other                                        28
all$year.studyL2 <- ifelse(all$year.studyL2 == "Other",all$other.year.studyL2.richi,all$year.studyL2 )
# European context
ggplot(all[all$Context == "English in Germany" | all$Context == "English in Italy",],aes(x=degree,fill=year.studyL2)) + geom_bar(position="dodge",colour="white") + theme_bw() + ggtitle("Degree by study year L2, by Context") +  facet_grid(~Context,scales="free") + theme(axis.text.x = element_text(angle = 45, hjust = 1)) + labs(y = "N participants", x = "degree")

  • Degree of enrolment
# Australian context
tabAge <- t(table(all[all$Context == "Italian in Australia" | all$Context == "German in Australia",'degree'],all[all$Context == "Italian in Australia" | all$Context == "German in Australia",'Context']))
ggplot(all[all$Context == "Italian in Australia" | all$Context == "German in Australia",],aes(x=Context,fill=degree)) + geom_bar(position="dodge",colour="white") + theme_bw() + ggtitle("Degree in Australian Contexts") + draw_grob(tableGrob(tabAge), x=1., y=40, width=0.3, height=0.4)

tabAge
                      
                       HUM HUM.SCI SCI
  German in Australia   48       4  36
  Italian in Australia  50       2  22
# Australian context
tabAge <- t(table(all[all$Context == "English in Italy" | all$Context == "English in Germany",'degree'],all[all$Context == "English in Italy" | all$Context == "English in Germany",'Context']))
ggplot(all[all$Context == "English in Italy" | all$Context == "English in Germany",],aes(x=Context,fill=degree)) + geom_bar(position="dodge",colour="white") + theme_bw() + ggtitle("Degree in European Contexts")

tabAge
                    
                     BA in Anglistik BA in Nordamerikastudien LA
  English in Germany              39                        4 27
  English in Italy                 0                        0  0
                    
                     Lingue e letterature straniere
  English in Germany                              0
  English in Italy                               78
                    
                     Lingue, mercati e culture dell'Asia
  English in Germany                                   0
  English in Italy                                    13

5 Australian context spcific variables

kable(table(all$reconnect.comm,all$Context))

English in Germany English in Italy German in Australia Italian in Australia
Agree 0 0 8 11
Disagree 0 0 35 14
Not sure 0 0 3 4
Strongly agree 0 0 12 28
Strongly disagree 0 0 30 17

kable(table(all$speakersmelb.comm,all$Context))

English in Germany English in Italy German in Australia Italian in Australia
Agree 0 0 44 41
Disagree 0 0 6 2
Not sure 0 0 25 12
Strongly agree 0 0 12 19
Strongly disagree 0 0 1 0

kable(table(all$comecloser.comm,all$Context))
English in Germany English in Italy German in Australia Italian in Australia
Agree 0 0 21 34
Disagree 0 0 16 6
Not sure 0 0 43 17
Strongly agree 0 0 6 17
Strongly disagree 0 0 2 0

6 Likert scales

  • Convert Likert scales to numbers
convertToNumber <- function(column){
  column <- factor(column,levels = c("Strongly disagree","Disagree","Not sure","Agree","Strongly agree"))
  column_number <- as.numeric(column)
  return(column_number)
}
table(all$Context)

  English in Germany     English in Italy  German in Australia 
                  70                   91                   88 
Italian in Australia 
                  74 
table(all$study.year)

1st semester     1st year 
          70          253 
convert_likert <- data.frame(apply(subset(all,select=likert_variables_all),2,convertToNumber))
colnames(convert_likert) <- paste0(colnames(convert_likert),"1")
likert_variables1 <- paste0(likert_variables_all,"1")
# join the converted variables to the filtered dataset
filtered_conv <- cbind(all,convert_likert)
table(filtered_conv[,likert_variables_all[4]],filtered_conv[,likert_variables1[4]],useNA = "always")
                   
                      1   2   3   4   5 <NA>
  Agree               0   0   0 121   0    0
  Disagree            0  10   0   0   0    0
  Not sure            0   0  39   0   0    0
  Strongly agree      0   0   0   0 152    0
  Strongly disagree   1   0   0   0   0    0
  <NA>                0   0   0   0   0    0
write.csv(filtered_conv,"02-descriptive_data/merged_filtered_likertNumber.csv",row.names = FALSE)

6.1 Impute missing values - Using median values

The missing values appears to be at random and there are max two missing values in one variable (see plots below). In order not to loose 12 participants while doing the factor analysis across contexts it is preferable to impute the 12 missing values.

all <- filtered_conv
# Items to use for factor analysis : items shared between contexts
# items to be used for the FA
usable_items <- likert_variables1[!(likert_variables1 %in% c("necessity1","educated1","reconnect.comm1", "speakersmelb.comm1", "comecloser.comm1"))]
rownames(all) <- all$Resp.ID
usable_data_context <- all[,c(usable_items,"Context")]
dat_noNA <- usable_data_context[rowSums(is.na(usable_data_context)) == 0,]
all_noNA <- all[rowSums(is.na(usable_data_context)) == 0,]
table(rowSums(is.na(usable_data_context)))

  0   1 
311  12 
# Participants with NA to remove
table(rowSums(is.na(usable_data_context)),usable_data_context$Context,useNA = "always")
      
       English in Germany English in Italy German in Australia
  0                    70               85                  87
  1                     0                6                   1
  <NA>                  0                0                   0
      
       Italian in Australia <NA>
  0                      69    0
  1                       5    0
  <NA>                    0    0
# Variable missing values
table(colSums(is.na(usable_data_context)))

 0  1  2 
19 10  1 
table(rowSums(is.na(usable_data_context)),usable_data_context$Context,useNA = "always")
      
       English in Germany English in Italy German in Australia
  0                    70               85                  87
  1                     0                6                   1
  <NA>                  0                0                   0
      
       Italian in Australia <NA>
  0                      69    0
  1                       5    0
  <NA>                    0    0
# check what to use to impute
# have a look at the distribution of missing values
library(mice)
Loading required package: lattice

Attaching package: ‘mice’

The following object is masked from ‘package:tidyr’:

    complete

The following objects are masked from ‘package:base’:

    cbind, rbind
library(VIM)
Loading required package: colorspace
Loading required package: grid
Loading required package: data.table
data.table 1.12.0  Latest news: r-datatable.com

Attaching package: ‘data.table’

The following objects are masked from ‘package:reshape2’:

    dcast, melt

The following objects are masked from ‘package:dplyr’:

    between, first, last

The following object is masked from ‘package:purrr’:

    transpose

VIM is ready to use. 
 Since version 4.0.0 the GUI is in its own package VIMGUI.

          Please use the package to use the new (and old) GUI.

Suggestions and bug-reports can be submitted at: https://github.com/alexkowa/VIM/issues

Attaching package: ‘VIM’

The following object is masked from ‘package:datasets’:

    sleep
mice_plot <- aggr(usable_data_context[,usable_items], col=c('navyblue','yellow'),
                    numbers=TRUE, sortVars=TRUE,
                    labels=names(usable_data_context[,usable_items]), cex.axis=.4,
                    gap=1, ylab=c("Missing data","Pattern"),cex.numbers=0.5)

 Variables sorted by number of missings: 

# Imputing using median
library(Hmisc)
Loading required package: survival
Loading required package: Formula

Attaching package: ‘Hmisc’

The following object is masked from ‘package:sjmisc’:

    %nin%

The following object is masked from ‘package:psych’:

    describe

The following objects are masked from ‘package:dplyr’:

    src, summarize

The following objects are masked from ‘package:base’:

    format.pval, units
imputedMedian <- usable_data_context
imputedMedian$globalaccess.post1 <- with(imputedMedian[,usable_items], impute(globalaccess.post1, median))
imputedMedian$citizen.post1 <- with(imputedMedian[,usable_items], impute(citizen.post1, median))
imputedMedian$money.instru1 <- with(imputedMedian[,usable_items], impute(money.instru1, median))
imputedMedian$knowledge.instru1 <- with(imputedMedian[,usable_items], impute(knowledge.instru1, median))
imputedMedian$life.intr1 <- with(imputedMedian[,usable_items], impute(life.intr1, median))
imputedMedian$time.integr1 <- with(imputedMedian[,usable_items], impute(time.integr1, median))
imputedMedian$expect.ought1 <- with(imputedMedian[,usable_items], impute(expect.ought1, median))
imputedMedian$job.instru1 <- with(imputedMedian[,usable_items], impute(job.instru1, median))
imputedMedian$career.instru1 <- with(imputedMedian[,usable_items], impute(career.instru1, median))
imputedMedian$meeting.integr1 <- with(imputedMedian[,usable_items], impute(meeting.integr1, median))
imputedMedian$interact.post1 <- with(imputedMedian[,usable_items], impute(interact.post1, median))
# check before after
table(imputedMedian$time.integr1)

  2   3   4   5 
  3  21  95 204 
table(usable_data_context$time.integr1)

  2   3   4   5 
  3  21  95 202 
table(imputedMedian$life.intr1)

  1   2   3   4   5 
  8  79  81 117  38 
table(usable_data_context$life.intr1)

  1   2   3   4   5 
  8  79  80 117  38 
table(imputedMedian$knowledge.instru1)

  1   2   3   4   5 
  1   2  29 189 102 
table(usable_data_context$knowledge.instru1)

  1   2   3   4   5 
  1   2  29 188 102 
table(imputedMedian$money.instru1)

  1   2   3   4   5 
  3  38 179  84  19 
table(usable_data_context$money.instru1)

  1   2   3   4   5 
  3  38 178  84  19 
table(imputedMedian$citizen.post1)

  1   2   3   4   5 
  3  22  75 148  75 
table(usable_data_context$citizen.post1)

  1   2   3   4   5 
  3  22  75 147  75 
table(imputedMedian$globalaccess.post1)

  1   2   3   4   5 
  1   3  20 159 140 
table(usable_data_context$globalaccess.post1)

  1   2   3   4   5 
  1   3  20 158 140 
table(imputedMedian$expect.ought1)

  1   2   3   4   5 
126 142  30  21   4 
table(usable_data_context$expect.ought1)

  1   2   3   4   5 
126 141  30  21   4 
table(imputedMedian$job.instru1)

  2   3   4   5 
 13 103 133  74 
table(usable_data_context$job.instru1)

  2   3   4   5 
 13 103 132  74 
table(imputedMedian$career.instru1)

  1   2   3   4   5 
  1   1  63 131 127 
table(usable_data_context$career.instru1)

  1   2   3   4   5 
  1   1  63 130 127 
table(imputedMedian$meeting.integr1)

  2   3   4   5 
  1  10 121 191 
table(usable_data_context$meeting.integr1)

  2   3   4   5 
  1  10 121 190 
table(imputedMedian$interact.post1)

  2   3   4   5 
  1  19 140 163 
table(usable_data_context$interact.post1)

  2   3   4   5 
  1  19 140 162 
  • Substitute imputed data for the common variables to be used in the Factor Analysis
all <- all[,!(colnames(all) %in% usable_items)]
imputedMedian$Context <- NULL
sum(!(colnames(imputedMedian) %in% usable_items))
[1] 0
all <- cbind(all,imputedMedian[match(rownames(imputedMedian),all$Resp.ID),])

Add some updates that Richi did in Date 7th June 2018

Other_ways_and_degree_role_with_respondent_IDs <- read_excel("Other-ways-and-degree-role-with-respondent-IDs.xlsx")
sum(Other_ways_and_degree_role_with_respondent_IDs$Resp.ID != Other_ways_and_degree_role_with_respondent_IDs$Resp.ID__1)
# to replace 
# match for the NA degree.role

match_updates <- match(all$Resp.ID,Other_ways_and_degree_role_with_respondent_IDs$Resp.ID)
all$private.lessons1.other.ways[match_updates] <- Other_ways_and_degree_role_with_respondent_IDs$private.lessons1.other.ways
all$study.holiday2.other.ways[match_updates] <- Other_ways_and_degree_role_with_respondent_IDs$study.holiday2.other.ways
all$year.sem.abroad3.other.ways[match_updates] <- Other_ways_and_degree_role_with_respondent_IDs$year.sem.abroad3.other.ways
all$online.course4.other.ways[match_updates] <- Other_ways_and_degree_role_with_respondent_IDs$online.course4.other.ways
all$other5.other.ways[match_updates] <- Other_ways_and_degree_role_with_respondent_IDs$other5.other.ways
all$degree.role[match_updates] <- Other_ways_and_degree_role_with_respondent_IDs$degree.role

6.2 Save imputed data

write.csv(all,"02-descriptive_data/merged_filtered_imputedMedian_likertNumber.csv",row.names = FALSE)

7 Barplot of likert variables

all_melt <- melt(all,id.vars = c("Resp.ID","Gender","Age","prof","Context","study.year"),
                        measure.vars = likert_variables1)
attributes are not identical across measure variables; they will be dropped
all_melt$value <- factor(all_melt$value,levels=c(1,2,3,4,5),labels=c("Strongly disagree","Disagree","Not sure","Agree","Strongly agree"))
# dim(all_melt)
# 323*length(likert_variables1)
all_melt <- all_melt %>% separate(variable,into=c("item","type"),sep="\\.",remove=FALSE)
Expected 2 pieces. Missing pieces filled with `NA` in 646 rows [9368, 9369, 9370, 9371, 9372, 9373, 9374, 9375, 9376, 9377, 9378, 9379, 9380, 9381, 9382, 9383, 9384, 9385, 9386, 9387, ...].
ggplot(all_melt,aes(x=variable,fill=value)) + geom_bar(position = "stack",colour="black") + 
  facet_grid(Context~type,scales = "free")+theme(axis.text.x = element_text(angle = 45, hjust = 1),axis.text=element_text(size=8)) + ggtitle("Filtered dataset") + scale_fill_manual(values=c("#ca0020","#f4a582","#ffffbf","#abd9e9","#2c7bb6","grey"))

filt_sum <- all_melt %>% group_by(Context,variable,type,value) %>% dplyr::summarise(Ngroup=length(value))
Factor `value` contains implicit NA, consider using `forcats::fct_explicit_na`
ggplot(filt_sum,aes(x=value,y=Ngroup,colour=Context,group=interaction(variable, Context))) + geom_line() + geom_point() + facet_wrap(~type,scales = "free")+theme(axis.text.x = element_text(angle = 45, hjust = 1))

7.1 Barplot of Educated and Necessity in the Australian and European Contexts

  • Educated
# add numbers on the bar
educated <- all[all$Context %in% c("German in Australia","Italian in Australia"),]
table(educated$educated1,educated$Context,useNA="always")
      
       German in Australia Italian in Australia <NA>
  1                     11                    9    0
  2                     25                   24    0
  3                     12                   13    0
  4                     29                   18    0
  5                     11                   10    0
  <NA>                   0                    0    0
educated$educated1 <- factor(educated$educated1,levels = c(1,2,3,4,5),labels=c("Strongly disagree","Disagree","Not sure","Agree","Strongly agree")) 
tabEdu <- t(table(educated$educated1,educated$Context))
ggdf <- data.frame(Educated = rep(colnames(tabEdu),each=2),
  N.Participants = as.numeric(tabEdu),
  Context = rep(rownames(tabEdu),times=5))
ggplot(ggdf,aes(x=Educated,y=N.Participants,fill=Context)) + geom_bar(position="dodge",colour="white",stat="identity")  + labs(y="N participants") + scale_y_continuous(breaks=seq(0,35,10),limits=c(0,35)) + theme_bw() + ggtitle("Educated by Context")+  geom_text(aes(label = N.Participants), hjust=0.5, vjust=-0.25, size = 2.5,position=position_dodge(width=0.9)) 

ggplot(ggdf,aes(x=Context,y=N.Participants,fill=Educated)) + geom_bar(position="dodge",colour="white",stat="identity")  + labs(y="N participants") + scale_y_continuous(breaks=seq(0,35,10),limits=c(0,35)) + theme_bw() + ggtitle("Educated by Context")+  geom_text(aes(label = N.Participants), hjust=0.5, vjust=-0.25, size = 2.5,position=position_dodge(width=0.9)) 

  • Necessity
# add numbers on the bar
necessity <- all[all$Context %in% c("English in Germany","English in Italy"),]
table(necessity$necessity1,necessity$Context,useNA="always")
      
       English in Germany English in Italy <NA>
  1                     1               12    0
  2                     7               16    0
  3                    13                6    0
  4                    32               36    0
  5                    16               20    0
  <NA>                  1                1    0
necessity$necessity1 <- factor(necessity$necessity1,levels = c(1,2,3,4,5),labels=c("Strongly disagree","Disagree","Not sure","Agree","Strongly agree")) 
tabNec <- t(table(necessity$necessity1,necessity$Context,useNA = "always"))[-3,]
ggdf <- data.frame(Necessity = rep(colnames(tabNec),each=2),
  N.Participants = as.numeric(tabNec),
  Context = rep(rownames(tabNec),times=6))
ggplot(ggdf,aes(x=Necessity,y=N.Participants,fill=Context)) + geom_bar(position="dodge",colour="white",stat="identity")  + labs(y="N participants") + scale_y_continuous(breaks=seq(0,40,10),limits=c(0,40)) + theme_bw() + ggtitle("Necessity by Context")+  geom_text(aes(label = N.Participants), hjust=0.5, vjust=-0.25, size = 2.5,position=position_dodge(width=0.9)) 

ggplot(ggdf,aes(x=Context,y=N.Participants,fill=Necessity)) + geom_bar(position="dodge",colour="white",stat="identity")  + labs(y="N participants") + scale_y_continuous(breaks=seq(0,35,10),limits=c(0,35)) + theme_bw() + ggtitle("Necessity by Context")+  geom_text(aes(label = N.Participants), hjust=0.5, vjust=-0.25, size = 2.5,position=position_dodge(width=0.9)) 

8 Correlation plot of items by context

8.1 Italian in Australia

cov <- cor(filtered_conv[filtered_conv$Context == "Italian in Australia",likert_variables1[!(likert_variables1 %in% "necessity1")]],method = "pearson",use="pairwise.complete.obs")
data_cor_ita_in_au <- data.frame(cor_ita_in_au=cov[lower.tri(cov, diag = TRUE)],
                var1 = rownames(cov)[unlist(t(mapply(":", 1:nrow(cov), nrow(cov)))[1,])],
                var2 = rep(colnames(cov),times=rev(seq(nrow(cov):1))))
row_infos <- data.frame(Variables=sapply(strsplit(colnames(cov),split="\\."),function(x) x[2]))
row_infos$Variables <- as.character(row_infos$Variables)
rownames(row_infos) <- rownames(cov)
row_infos$Variables[which(is.na(row_infos$Variables))] <- c("educated")
row_infos <- row_infos[order(row_infos$Variables),,drop=FALSE]
ann_col_wide <- data.frame(Variable=unique(row_infos$Variables))
ann_colors_wide <- list(Variables=c(comm1="#bd0026",educated="#b35806", id1="#f6e8c3",instru1="#35978f",integr1="#386cb0",intr1="#ffff99",ought1="grey",post1="black",prof1="pink"))
#pheatmap(cov, main = "Italian in Australia",annotation_names_row = FALSE,cluster_cols=TRUE,cluster_rows=TRUE,annotation_col = row_infos[,1,drop=FALSE], annotation_row = row_infos[,1,drop=FALSE],  annotation_colors = ann_colors_wide,breaks=seq(-1,1,0.2),col=c("#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"),show_colnames = FALSE,width = 7,height = 7)
###################
diag(cov) <- NA
pheatmap(cov, main = "Italian in Australia",annotation_names_row = FALSE,cluster_cols=TRUE,cluster_rows=TRUE,annotation_col = row_infos[,1,drop=FALSE], annotation_row = row_infos[,1,drop=FALSE]
,  annotation_colors = ann_colors_wide,show_colnames = FALSE,breaks = seq(-0.6,0.7,length.out = 50),width = 7,height = 7,color=colorRampPalette(brewer.pal(n = 7, name = "RdBu"))(50))

cov_ItaAus <- cov

8.2 German in Australia

cov <- cor(filtered_conv[filtered_conv$Context == "German in Australia",likert_variables1[!(likert_variables1 %in% "necessity1")]],method = "pearson",use="pairwise.complete.obs")
data_cor_germ_in_au <- data.frame(cor_germ_in_au=cov[lower.tri(cov, diag = TRUE)],
                var1 = rownames(cov)[unlist(t(mapply(":", 1:nrow(cov), nrow(cov)))[1,])],
                var2 = rep(colnames(cov),times=rev(seq(nrow(cov):1))))
row_infos <- data.frame(Variables=sapply(strsplit(colnames(cov),split="\\."),function(x) x[2]))
row_infos$Variables <- as.character(row_infos$Variables)
rownames(row_infos) <- rownames(cov)
row_infos$Variables[which(is.na(row_infos$Variables))] <- c("educated")
row_infos <- row_infos[order(row_infos$Variables),,drop=FALSE]
ann_col_wide <- data.frame(Variable=unique(row_infos$Variables))
ann_colors_wide <- list(Variables=c(comm1="#bd0026",educated="#b35806", id1="#f6e8c3",instru1="#35978f",integr1="#386cb0",intr1="#ffff99",ought1="grey",post1="black",prof1="pink"))
diag(cov) <- NA
pheatmap(cov, main = "German in Australia",annotation_names_row = FALSE,cluster_cols=TRUE,cluster_rows=TRUE,annotation_col = row_infos[,1,drop=FALSE], annotation_row = row_infos[,1,drop=FALSE]
,  annotation_colors = ann_colors_wide,show_colnames = FALSE,breaks = seq(-0.6,0.7,length.out = 50),width = 7,height = 7,color=colorRampPalette(brewer.pal(n = 7, name = "RdBu"))(50))

# 
cov_GermAus <- cov

8.3 English in Germany

cov <- cor(filtered_conv[filtered_conv$Context == "English in Germany",likert_variables1[!(likert_variables1 %in% c("reconnect.comm1",    "speakersmelb.comm1","comecloser.comm1","educated1"))]],method = "pearson",use="pairwise.complete.obs")
data_cor_eng_in_germ <- data.frame(cor_eng_in_germ=cov[lower.tri(cov, diag = TRUE)],
                var1 = rownames(cov)[unlist(t(mapply(":", 1:nrow(cov), nrow(cov)))[1,])],
                var2 = rep(colnames(cov),times=rev(seq(nrow(cov):1))))
row_infos <- data.frame(Variables=sapply(strsplit(colnames(cov),split="\\."),function(x) x[2]))
row_infos$Variables <- as.character(row_infos$Variables)
rownames(row_infos) <- rownames(cov)
row_infos$Variables[which(is.na(row_infos$Variables))] <- c("necessity")
row_infos <- row_infos[order(row_infos$Variables),,drop=FALSE]
ann_col_wide <- data.frame(Variable=unique(row_infos$Variables))
ann_colors_wide <- list(Variables=c(id1="#f6e8c3",necessity="#b35806",instru1="#35978f",integr1="#386cb0",intr1="#ffff99",ought1="grey",post1="black",prof1="pink"))
diag(cov) <- NA
pheatmap(cov, main = "English in Germany",annotation_names_row = FALSE,cluster_cols=TRUE,cluster_rows=TRUE,annotation_col = row_infos[,1,drop=FALSE], annotation_row = row_infos[,1,drop=FALSE]
,  annotation_colors = ann_colors_wide,show_colnames = FALSE,breaks = seq(-0.6,0.7,length.out = 50),width = 7,height = 7,color=colorRampPalette(brewer.pal(n = 7, name = "RdBu"))(50))

cov_EngGerm <- cov

8.4 English in Italy

cov <- cor(filtered_conv[filtered_conv$Context == "English in Italy",likert_variables1[!(likert_variables1 %in% c("reconnect.comm1","speakersmelb.comm1","comecloser.comm1","educated1"))]],method = "pearson",use="pairwise.complete.obs")
data_cor_eng_in_ita <- data.frame(cor_eng_in_ita=cov[lower.tri(cov, diag = TRUE)],
                var1 = rownames(cov)[unlist(t(mapply(":", 1:nrow(cov), nrow(cov)))[1,])],
                var2 = rep(colnames(cov),times=rev(seq(nrow(cov):1))))
row_infos <- data.frame(Variables=sapply(strsplit(colnames(cov),split="\\."),function(x) x[2]))
row_infos$Variables <- as.character(row_infos$Variables)
rownames(row_infos) <- rownames(cov)
row_infos$Variables[which(is.na(row_infos$Variables))] <- "necessity"
row_infos <- row_infos[order(row_infos$Variables),,drop=FALSE]
ann_col_wide <- data.frame(Variable=unique(row_infos$Variables))
ann_colors_wide <- list(Variables=c(comm1="#bd0026",necessity="#b35806", id1="#f6e8c3",instru1="#35978f",integr1="#386cb0",intr1="#ffff99",ought1="grey",post1="black",prof1="pink"))
diag(cov) <- NA
pheatmap(cov, main = "English in Italy",annotation_names_row = FALSE,cluster_cols=TRUE,cluster_rows=TRUE,annotation_col = row_infos[,1,drop=FALSE], annotation_row = row_infos[,1,drop=FALSE]
,  annotation_colors = ann_colors_wide,show_colnames = FALSE,breaks = seq(-0.6,0.7,length.out = 50),width = 7,height = 7,color=colorRampPalette(brewer.pal(n = 7, name = "RdBu"))(50))

# 
cov_EngIta <- cov

8.5 Correlation between correlation in the different contexts

We will perform an exploratory FA combining all the contexts together. This means that we are assuming that the correlation between items across context has the same direction (does not happen that cor(item1,item2)_context1 > 0 and cor(item1,item2)_context2 < 0).

common <- rownames(cov_EngIta)[rownames(cov_EngIta) %in% rownames(cov_ItaAus)]
sum(rownames(cov_EngIta) != rownames(cov_EngGerm))
sum(rownames(cov_EngIta) != rownames(cov_GermAus))
sum(rownames(cov_EngIta) != rownames(cov_ItaAus))
sum(rownames(cov_GermAus) != rownames(cov_ItaAus))

common_EngIta <- cov_EngIta[rownames(cov_EngIta) %in% common,colnames(cov_EngIta) %in% common]
common_EngGerm <- cov_EngGerm[rownames(cov_EngGerm) %in% common,colnames(cov_EngGerm) %in% common]
common_GermAus <- cov_GermAus[rownames(cov_GermAus) %in% common,colnames(cov_GermAus) %in% common]
common_ItaAus <- cov_ItaAus[rownames(cov_ItaAus) %in% common,colnames(cov_ItaAus) %in% common]

sum(rownames(common_EngIta) != colnames(common_EngIta))
sum(rownames(common_EngGerm) != colnames(common_EngGerm))
sum(rownames(common_GermAus) != colnames(common_GermAus))
sum(rownames(common_ItaAus) != colnames(common_ItaAus))


par(mfrow=c(2,3))
plot(common_EngIta,common_EngGerm)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")
plot(common_EngIta,common_GermAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")
plot(common_EngIta,common_ItaAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")

plot(common_EngGerm,common_GermAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")
plot(common_EngGerm,common_ItaAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")

plot(common_GermAus,common_ItaAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")

# Largest differences
low_EngGerm <- lower.tri(common_EngGerm)
common_EngGerm[!low_EngGerm] <- NA
common_GermAus[!(lower.tri(common_GermAus))] <- NA
common_ItaAus[!(lower.tri(common_ItaAus))] <- NA
common_EngIta[!(lower.tri(common_EngIta))] <- NA


mat <- data.frame(common_EngGerm=c(common_EngGerm),
                  common_EngIta=c(common_EngIta),
                  common_GermAus = c(common_GermAus),
                  common_ItaAus = c(common_ItaAus),
                  compare = paste(rownames(common_EngGerm),colnames(common_EngGerm),sep=".")) %>%
  filter(!is.na(common_EngGerm)) %>%
  separate(compare,into=c("item1","variable1","item2","variable2"),remove=FALSE,sep="[.]") %>%
  unite(group,variable1,variable2,sep=".")

library(ggrepel)
ggplot(mat,aes(x=common_EngGerm,y=common_GermAus,label=compare,colour=group)) + geom_point(alpha=0.5,size=0.8) + geom_text(size=2) +
  geom_hline(yintercept=c(0,0.3),linetype="dotted",colour="dark red") +
geom_vline(xintercept=c(0,0.3),linetype="dotted",colour="dark red")


ggplot(mat,aes(x=common_EngGerm,y=common_ItaAus,label=compare,colour=group)) + geom_point(alpha=0.5,size=0.8) + geom_text(size=2) +
  geom_hline(yintercept=c(0,0.3),linetype="dotted",colour="dark red") +
geom_vline(xintercept=c(0,0.3),linetype="dotted",colour="dark red")

ggplot(mat,aes(x=common_EngGerm,y=common_EngIta,label=compare,colour=group)) + geom_point(alpha=0.5,size=0.8) + geom_text(size=2) +
  geom_hline(yintercept=c(0,0.3),linetype="dotted",colour="dark red") +
geom_vline(xintercept=c(0,0.3),linetype="dotted",colour="dark red")

8.6 Different correlation plot and Pearson’s correlation

cowplot::plot_grid(p1,p2,p3,p4,p5,p6,nrow=3)
knitr::kable(cor_data)

8.7 All context together

cov <- cor(filtered_conv[,likert_variables1],method = "pearson",use="pairwise.complete.obs")

row_infos <- data.frame(Variables=sapply(strsplit(colnames(cov),split="\\."),function(x) x[2]))
row_infos$Variables <- as.character(row_infos$Variables)
rownames(row_infos) <- rownames(cov)
row_infos$Variables[which(is.na(row_infos$Variables))] <- c("necessity","educated")
row_infos <- row_infos[order(row_infos$Variables),,drop=FALSE]

ann_col_wide <- data.frame(Variable=unique(row_infos$Variables))
ann_colors_wide <- list(Variables=c(comm1="#bd0026",educated="orange", id1="#f6e8c3",instru1="#35978f",necessity="#b35806",integr1="#386cb0",intr1="#ffff99",ought1="grey",post1="black",prof1="pink"))

diag(cov) <- NA
pheatmap(cov, main = "All Contexts",annotation_names_row = FALSE,cluster_cols=TRUE,cluster_rows=TRUE,annotation_col = row_infos[,1,drop=FALSE], annotation_row = row_infos[,1,drop=FALSE]
,  annotation_colors = ann_colors_wide,show_colnames = FALSE,breaks = seq(-0.6,0.7,length.out = 50),width = 7,height = 7,color=colorRampPalette(brewer.pal(n = 7, name = "RdBu"))(50))

8.8 Compare correlations

library(GGally)
combine_cor <- merge(data_cor_eng_in_ita,data_cor_eng_in_germ,all = TRUE)
combine_cor1 <- merge(combine_cor,data_cor_germ_in_au,all = TRUE)
combine_cor2 <- merge(combine_cor1,data_cor_ita_in_au,all = TRUE)
combine_cor2 <- combine_cor2 %>% separate(var1,into=c("item1","variable1"),sep="[.]",remove=FALSE) %>%
  separate(var2,into=c("item2","variable2"),sep="[.]",remove=FALSE) %>%
  unite(group,variable1,variable2,sep=".")

pairs(combine_cor2[,c("cor_eng_in_ita","cor_eng_in_germ","cor_germ_in_au","cor_ita_in_au")])
ggpairs(combine_cor2[,c("cor_eng_in_ita","cor_eng_in_germ","cor_germ_in_au","cor_ita_in_au")])

8.9 Correlation between correlation in the different contexts

We will perform an exploratory FA combining all the contexts together. This means that we are assuming that the correlation between items across context has the same direction (does not happen that cor(item1,item2)_context1 > 0 and cor(item1,item2)_context2 < 0).

common <- rownames(cov_EngIta)[rownames(cov_EngIta) %in% rownames(cov_ItaAus)]
sum(rownames(cov_EngIta) != rownames(cov_EngGerm))
sum(rownames(cov_EngIta) != rownames(cov_GermAus))
sum(rownames(cov_EngIta) != rownames(cov_ItaAus))
sum(rownames(cov_GermAus) != rownames(cov_ItaAus))

common_EngIta <- cov_EngIta[rownames(cov_EngIta) %in% common,colnames(cov_EngIta) %in% common]
common_EngGerm <- cov_EngGerm[rownames(cov_EngGerm) %in% common,colnames(cov_EngGerm) %in% common]
common_GermAus <- cov_GermAus[rownames(cov_GermAus) %in% common,colnames(cov_GermAus) %in% common]
common_ItaAus <- cov_ItaAus[rownames(cov_ItaAus) %in% common,colnames(cov_ItaAus) %in% common]

sum(rownames(common_EngIta) != colnames(common_EngIta))
sum(rownames(common_EngGerm) != colnames(common_EngGerm))
sum(rownames(common_GermAus) != colnames(common_GermAus))
sum(rownames(common_ItaAus) != colnames(common_ItaAus))


par(mfrow=c(2,3))
plot(common_EngIta,common_EngGerm)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")
plot(common_EngIta,common_GermAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")
plot(common_EngIta,common_ItaAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")

plot(common_EngGerm,common_GermAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")
plot(common_EngGerm,common_ItaAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")

plot(common_GermAus,common_ItaAus)
abline(h=c(0,0.3),v=c(0,0.3),lty=2,col = "dark red")
abline(a=0,b=1,lty=2,col = "dark red")

# Largest differences
low_EngGerm <- lower.tri(common_EngGerm)
common_EngGerm[!low_EngGerm] <- NA
common_GermAus[!(lower.tri(common_GermAus))] <- NA
common_ItaAus[!(lower.tri(common_ItaAus))] <- NA
common_EngIta[!(lower.tri(common_EngIta))] <- NA


mat <- data.frame(common_EngGerm=c(common_EngGerm),
                  common_EngIta=c(common_EngIta),
                  common_GermAus = c(common_GermAus),
                  common_ItaAus = c(common_ItaAus),
                  compare = paste(rownames(common_EngGerm),colnames(common_EngGerm),sep=".")) %>%
  filter(!is.na(common_EngGerm)) %>%
  separate(compare,into=c("item1","variable1","item2","variable2"),remove=FALSE,sep="[.]") %>%
  unite(group,variable1,variable2,sep=".")

library(ggrepel)
ggplot(mat,aes(x=common_EngGerm,y=common_GermAus,label=compare,colour=group)) + geom_point(alpha=0.5,size=0.8) + geom_text(size=2) +
  geom_hline(yintercept=c(0,0.3),linetype="dotted",colour="dark red") +
geom_vline(xintercept=c(0,0.3),linetype="dotted",colour="dark red")


ggplot(mat,aes(x=common_EngGerm,y=common_ItaAus,label=compare,colour=group)) + geom_point(alpha=0.5,size=0.8) + geom_text(size=2) +
  geom_hline(yintercept=c(0,0.3),linetype="dotted",colour="dark red") +
geom_vline(xintercept=c(0,0.3),linetype="dotted",colour="dark red")

ggplot(mat,aes(x=common_EngGerm,y=common_EngIta,label=compare,colour=group)) + geom_point(alpha=0.5,size=0.8) + geom_text(size=2) +
  geom_hline(yintercept=c(0,0.3),linetype="dotted",colour="dark red") +
geom_vline(xintercept=c(0,0.3),linetype="dotted",colour="dark red")

9 Evaluate internal consistency of known constructs with alpha

sets <- list(id.var=likert_variables1[grep("\\.id1$",likert_variables1)],
             ought.var=likert_variables1[grep("\\.ought1$",likert_variables1)],
             intr.var=likert_variables1[grep("\\.intr1$",likert_variables1)],
             instru.var=likert_variables1[grep("\\.instru1$",likert_variables1)],
             integr1.var=likert_variables1[grep("\\.integr1$",likert_variables1)],
             prof.var=likert_variables1[grep("\\.prof1$",likert_variables1)],
             post.var=likert_variables1[grep("\\.post1$",likert_variables1)],
             comm.var=likert_variables1[grep("\\.comm1$",likert_variables1)])
              

get_alpha <- function(dataMot,
                      var=sets$id.var){
  var_alpha <- alpha(dataMot[,var])
  dataf <- data.frame(alpha=var_alpha$total,
                    drop = var_alpha$alpha.drop)
  rownames(dataf) <- rownames(var_alpha$alpha.drop)
  return(dataf)
}

# "Italian in Australia"
ita_in_au <- do.call(rbind,lapply(sets,function(x) {
  get_alpha(data=filtered_conv[filtered_conv$Context == "Italian in Australia",],
                      var=x)}))
ita_in_au$var <- sapply(strsplit(rownames(ita_in_au),split="\\."),function(x) x[1]) 
ita_in_au$var.full <- sapply(strsplit(rownames(ita_in_au),split="\\."),function(x) x[3]) 
ita_in_au$Context <- "Italian in Australia"
rownames(ita_in_au) <- NULL

# "German in Australia"
germ_in_au <- do.call(rbind,lapply(sets,function(x) {
  get_alpha(data=filtered_conv[filtered_conv$Context == "German in Australia",],
                      var=x)}))
germ_in_au$var <- sapply(strsplit(rownames(germ_in_au),split="\\."),function(x) x[1]) 
germ_in_au$var.full <- sapply(strsplit(rownames(germ_in_au),split="\\."),function(x) x[3]) 
germ_in_au$Context <- "German in Australia"
rownames(germ_in_au) <- NULL

# "English in Germany"
eng_in_germ <- do.call(rbind,lapply(sets[!(names(sets) %in% "comm.var")],function(x) {
  get_alpha(data=filtered_conv[filtered_conv$Context == "English in Germany",],
                      var=x)}))

# the ones that makes issues
get_alpha(data=filtered_conv[filtered_conv$Context == "English in Germany",],
                      var=sets$ought.var)

eng_in_germ$var <- sapply(strsplit(rownames(eng_in_germ),split="\\."),function(x) x[1]) 
eng_in_germ$var.full <- sapply(strsplit(rownames(eng_in_germ),split="\\."),function(x) x[3]) 
eng_in_germ$Context <- "English in Germany"
rownames(eng_in_germ) <- NULL

# "English in Italy"
eng_in_ita <- do.call(rbind,lapply(sets[!(names(sets) %in% "comm.var")],function(x) {
  get_alpha(data=filtered_conv[filtered_conv$Context == "English in Italy",],
                      var=x)}))
eng_in_ita$var <- sapply(strsplit(rownames(eng_in_ita),split="\\."),function(x) x[1]) 
eng_in_ita$var.full <- sapply(strsplit(rownames(eng_in_ita),split="\\."),function(x) x[3]) 
eng_in_ita$Context <- "English in Italy"
rownames(eng_in_ita) <- NULL


# combine
full_alpha <- rbind(eng_in_ita,eng_in_germ,germ_in_au,ita_in_au)
  • Plot alpha by variable

full_alpha %>% group_by(Context,var) %>% 
  summarise(st.alpha = unique(alpha.std.alpha),
            G6=unique(alpha.G6.smc.)) %>%
  ggplot(.,aes(x=var,y=st.alpha,colour=Context)) + geom_point() + geom_line(aes(group=Context)) + theme_bw()
all_melt <- all_melt %>% separate(variable,into=c("item","type"),sep="\\.",remove=FALSE)
p1=ggplot(all_melt,aes(x=variable,fill=value)) + geom_bar(position = "stack") + 
  facet_grid(Context~type,scales = "free") + ggtitle("Filtered dataset")+theme(axis.text.x = element_text(angle = 45, hjust = 1),axis.text=element_text(size=8))+theme_bw()

p2=ggplot(full_alpha,aes(x=var.full,y=drop.std.alpha,colour=Context)) + geom_point() + geom_line(aes(group=Context)) + theme_bw() + facet_wrap(~var,scales="free")

p4=ggplot(full_alpha,aes(x=var.full,y=drop.average_r,colour=Context)) + geom_point() + geom_line(aes(group=Context)) + theme_bw() + facet_wrap(~var,scales="free")

p3=full_alpha %>% group_by(Context,var) %>% 
  summarise(st.alpha = unique(alpha.std.alpha),
            G6=unique(alpha.G6.smc.)) %>%
  ggplot(.,aes(x=var,y=st.alpha,colour=Context)) + geom_point() + geom_line(aes(group=Context)) + theme(axis.text.x = element_text(angle = 45, hjust = 1),axis.text=element_text(size=8)) + theme_bw()


cowplot::plot_grid(p2,p3,nrow=2)
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgbWVyZ2VkIHF1ZXN0aW9ubmFpcmVzIgphdXRob3I6ICJBbm5hIFF1YWdsaWVyaSAmIFJpY2NhcmRvIEFtb3JhdGkiCmRhdGU6ICIwMy8wOS8yMDE3IgpvdXRwdXQ6CiAgZ2l0aHViX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnNCcKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKIyBQbGFuIHRoYXQgSSB3cm90ZSB3aXRoIFJpY2hpJ3MgY29tbWVudHMKCkxpbmsgYXQgaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vZG9jdW1lbnQvZC8xYmROZU9NQVlZOTBrOEZBYlBSV0dCZ1MxWUJFZFAwOWtQMHZjVzB0TmdQYy9lZGl0P3VzcD1zaGFyaW5nCgoKYGBge3IsbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KbGlicmFyeShyZWFkcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkocHN5Y2gpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoc2pQbG90KQpsaWJyYXJ5KHNqbGFiZWxsZWQpCmxpYnJhcnkoc2ptaXNjKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHJlYWR4bCkKCmRhdGEoZWZjKQp0aGVtZV9zZXQodGhlbWVfc2pwbG90KCkpCgojIENodW5rIG9wdGlvbnMKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBwcm9tcHQgPSBUUlVFLGNhY2hlID0gVFJVRSxmaWcud2lkdGggPSAxMixmaWcuaGVpZ2h0ID0gMTIpCgpgYGAKCiMgUmVhZCBpbiBkYXRhCgpgYGB7ciBtZXNzYWdlPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CmV1cm9wZWFuIDwtIHJlYWRfY3N2KCIwMS1jbGVhbmluZ19kYXRhX2RhdGEvZXVyb3BlYW5fcmVjb2RlZC5jc3YiKQphdXN0cmFsaWFuIDwtIHJlYWRfY3N2KCIwMS1jbGVhbmluZ19kYXRhX2RhdGEvYXVzdHJhbGlhbl9yZWNvZGVkLmNzdiIpCgpkaW0oZXVyb3BlYW4pCmRpbShhdXN0cmFsaWFuKQoKZXVyb3BlYW4kRVUgPC0gMQphdXN0cmFsaWFuJEFVIDwtIDEKCmFsbCA8LSBtZXJnZShldXJvcGVhbixhdXN0cmFsaWFuLGFsbCA9IFRSVUUpCgp0YWJsZShhbGwkRVUsYWxsJEFVLHVzZU5BID0gImFsd2F5cyIpCmBgYAoKIyMgVmFyaWFibGVzIHRvIGRlc2NyaWJlIGRhdGFzZXQgKGNhbiBiZSBkaWZmZXJlbnQgYmV0d2VlbiBjb250ZXh0cykKCmBgYHtyfQpkZW1vZ3JhcGhpY3NfdmFyIDwtIGMoIkFnZSIsIkdlbmRlciIsIkwxIiwic3BlYWsub3RoZXIuTDIiLCJzdHVkeS5vdGhlci5MMiIsIm9yaWdpbnMiLCJ5ZWFyLnN0dWR5TDIiLCJvdGhlcjUub3RoZXIud2F5cyIsImRlZ3JlZSIsInJvbGVMMi5kZWdyZWUiLCJzdHVkeS55ZWFyIiwicHJvZiIsIkwyLlZDRSIsInVuaTEueWVhciIsIkNvbnRleHQiKQpsMlNjaG9vbCA8LSAiXFwuTDJzY2hvb2wkIgpsMlNjaG9vbF92YXJpYWJsZXMgPC0gY29sbmFtZXMoYWxsKVtncmVwKGwyU2Nob29sLGNvbG5hbWVzKGFsbCkpXQpgYGAKCi0gRmlyc3QgbGFuZ3VhZ2UKCmBgYHtyfQojdGFibGUoYWxsJEwxLGFsbCRDb250ZXh0KSAjIHRvbyBtYW55IGxldmVscyAtIG5lZWRzIHRvIGJlIGNsZWFuZWQgKGV4IHRvdCBudW1iZXIgb2YgbGFuZ3VhZ2VzPykKdGFibGUoYWxsJEwxLHVzZU5BID0gImFsd2F5cyIpCmdncGxvdChhbGwsYWVzKHg9TDEsZmlsbD1Db250ZXh0KSkgKyBnZW9tX2JhcigpICsgY29vcmRfZmxpcCgpICsgZ2d0aXRsZSgiRmlyc3QgTGFuZ3VhZ2UiKSArIGxhYnMoeT0iTi4gb2YgcGFydGljaXBhbnRzIix4PSIiKSt0aGVtZV9idygpCiN0YWJsZShhbGwkc3BlYWsub3RoZXIuTDIsYWxsJENvbnRleHQpCmBgYAoKYGBge3J9CkwyIDwtIGRhdGEuZnJhbWUoRnJlcT10YWJsZShhbGwkc3BlYWsub3RoZXIuTDIpW29yZGVyKHRhYmxlKGFsbCRzcGVhay5vdGhlci5MMiksZGVjcmVhc2luZyA9IFRSVUUpXSwKICAgICAgICAgICAgICAgICBMMj1uYW1lcyh0YWJsZShhbGwkc3BlYWsub3RoZXIuTDIpKVtvcmRlcih0YWJsZShhbGwkc3BlYWsub3RoZXIuTDIpLGRlY3JlYXNpbmcgPSBUUlVFKV0pICMgdG9vIG1hbnkgbGV2ZWxzIC0gbmVlZHMgdG8gYmUgY2xlYW5lZCAoZXggdG90IG51bWJlciBvZiBsYW5ndWFnZXM/KQpoZWFkKEwyKQpgYGAKCi0gb3JpZ2lucwoKYGBge3J9CnRhYmxlKGFsbCRvcmlnaW5zLHVzZU5BID0gImFsd2F5cyIpCmBgYAoKCmBgYHtyfQp0YWJsZShhbGwkeWVhci5zdHVkeUwyKQpgYGAKCmBgYHtyfQp0YWJsZShhbGwkZGVncmVlKQpgYGAKCi0gc3R1ZHkueWVhciBpbiB0aGUgRXVyb3BlYW4gY29udGV4dCBpcyB1bmkxLnllYXIgaW4gdGhlIEF1c3RyYWxpYW4gY29udGV4dAoKYGBge3J9CmFsbCRzdHVkeS55ZWFyW2lzLm5hKGFsbCRzdHVkeS55ZWFyKV0gPC0gYWxsJHVuaTEueWVhcltpcy5uYShhbGwkc3R1ZHkueWVhcildCiN0YWJsZShhbGwkc3R1ZHkueWVhcikKYWxsJHN0dWR5LnllYXIgPC0gaWZlbHNlKGFsbCRzdHVkeS55ZWFyID09ICJBbHJlYWR5IGdyYWR1YXRlZCBhZnRlciA1IHNlbWVzdGVycyBpbiBNYXJjaCAyMDE2LCB3YXMgaW50ZXJlc3RlZCBpbiBzdXJ2ZXJ5L3N0dWR5LCBzb3JyeS4iLCI2dGggc2VtZXN0ZXIiLGFsbCRzdHVkeS55ZWFyKQp0YWJsZShhbGwkc3R1ZHkueWVhcikKYGBgCgotIHByb2ZpY2llbmN5CgpgYGB7cn0KdGFibGUoYWxsJHByb2YsdXNlTkEgPSAiYWx3YXlzIikKYGBgCgojIEZpbHRlciBwYXJ0aWNpcGFudHMgOiBrZWVwIG9ubHkgdGhlIG9uZXMgdGhhdCBtZWV0IHRoZSBpbmNsdXNpb24gY3JpdGVyaWEKCmBgYHtyIEZpbHRlcmVkLGZpZy53aWR0aD0yMCxmaWcuaGVpZ2h0PTE1fQphbGwkc3R1ZHkueWVhcltpcy5uYShhbGwkc3R1ZHkueWVhcildIDwtIGFsbCR1bmkxLnllYXJbaXMubmEoYWxsJHN0dWR5LnllYXIpXQojIEZpbHRlciBvbmx5IHN1YmplY3QgdGhhdCB3ZSB3YW50IHRvIGluY2x1ZGUgaW4gdGhlIHN0dWR5CiMgbmFtZXModGFibGUoYWxsJHN0dWR5LnllYXIpKVsxXSA9IDFzdCBzZW1lc3RlciIKCmZpbHRlcmVkIDwtIHN1YnNldChhbGwsIChzdHVkeS55ZWFyID09ICIxc3QgeWVhciIpIHwgKHN0dWR5LnllYXIgPT0gbmFtZXModGFibGUoYWxsJHN0dWR5LnllYXIpKVsxXSkpCiMmIHllYXIuc3R1ZHlMMiAhPSAiMCB5ZWFycyIKCmBgYAoKCiMjIEltcHV0aW5nIGRlZ3JlZSBiYXNlZCBvbiBRdWFsaXR5IENvbW1lbnRzIHByb3ZpZGVkIGluIHRoZSBxdWVzdGlvbnMKCi0gKio1MzEzOTc2NzE2KiogOiBTQ0kgKHdpc2ggdG8gc3R1ZHkgc2NpZW5jZSBpbiB0aGUgZnV0dXJlKQotICoqNTM1OTg2NjU0NSoqIDogSFVNLlNDSSAoYmFzZWQgb24gZGVncmVlLm90aGVyNykKLSAqKjUzNzUzNzAxMjIqKiA6IFNDSSAoc2hlIHdhbnRzIHRvIGRvIHNjaWVuY2UpCi0gKio1Mzc1Mzc2NzYxKiogOiBIVU0gKHNoZSB3YW50cyB0byBkbyB0cmFuc2xhdGlvbi9yZXNlcmFjaC90ZWFjaGluZykKCmBgYHtyfQpmaWx0ZXJlZCRkZWdyZWVbZmlsdGVyZWQkUmVzcC5JRCAlaW4lICI1MzEzOTc2NzE2Il0gPC0gIlNDSSIKZmlsdGVyZWQkZGVncmVlW2ZpbHRlcmVkJFJlc3AuSUQgJWluJSAiNTM1OTg2NjU0NSJdIDwtICJIVU0uU0NJIgpmaWx0ZXJlZCRkZWdyZWVbZmlsdGVyZWQkUmVzcC5JRCAlaW4lICI1Mzc1MzcwMTIyIl0gPC0gIlNDSSIKZmlsdGVyZWQkZGVncmVlW2ZpbHRlcmVkJFJlc3AuSUQgJWluJSAiNTM3NTM3Njc2MSJdIDwtICJIVU0iCgp0YWJsZShmaWx0ZXJlZCRkZWdyZWUpCmthYmxlKHRhYmxlKGZpbHRlcmVkJENvbnRleHQpKQprYWJsZSh0YWJsZShmaWx0ZXJlZCR5ZWFyLnN0dWR5TDIsZmlsdGVyZWQkQ29udGV4dCkpCmthYmxlKHRhYmxlKGZpbHRlcmVkJHllYXIuc3R1ZHlMMixmaWx0ZXJlZCRwcm9mKSkKa2FibGUodGFibGUoZmlsdGVyZWQkeWVhci5zdHVkeUwyLGZpbHRlcmVkJENvbnRleHQpKQpgYGAKClBlb3BsZSB0aGF0IGhhdmUgc3R1ZGllZCAwIHllYXJzIEwyIGFyZSBqdXN0IGEgc21hbGwgc3Vic2V0IG9mIHRoZSBHZXJtYW4gaW4gQXVzdHJhbGlhIGFuZCBJdGFsaWFuIGluIEF1c3RyYWxpYSBjb250ZXh0IHdoaWNoIG1lYW5zIHRoYXQgYnkgY29ycmVjdGluZyBmb3IgY29udGV4dCB3ZSBhcmUgbm90IHJlbW92aW5nIHRoZSBlZmZlY3Qgb2YgdGhlIDAgeWVhcnMuIEEgd2F5IHRvIHJlbW92ZSB0aGUgZWZmZWN0IG9mIHRoZSAwIHllYXJzIHBhcnRpY2lwYW50cyBhbmQgbm90IGluY2x1ZGluZyB0b28gbWFueSB2YXJpYWJsZXMgY291bGQgYmUgdG8gZXN0aW1hdGUgdGhlIGVmZmVjdCBvZiAwIHllYXJzIHZzIGFsbC4gCgojIERlZmluZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMKCiMjIE5lZWQgdG8gY2hlY2sgZGF0YXNldHMgd2l0aCBSY2loaSAod2h5IGRvIHdlIGhhdmUgUUMgaW4gTDE/IEFtIEkgdXNpbmcgbm90IHRoZSBsYXRlc3QgZGF0YXNldD8pCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQphbGwgPC0gZmlsdGVyZWQKZGVtb2dyYXBoaWNzX3ZhciA8LSBjKCJBZ2UiLCJHZW5kZXIiLCJMMSIsInNwZWFrLm90aGVyLkwyIiwic3R1ZHkub3RoZXIuTDIiLCJvcmlnaW5zIiwieWVhci5zdHVkeUwyIiwib3RoZXI1Lm90aGVyLndheXMiLCJkZWdyZWUiLCJyb2xlTDIuZGVncmVlIiwic3R1ZHkueWVhciIsInByb2YiLCJMMi5WQ0UiLCJ1bmkxLnllYXIiLCJDb250ZXh0IikKbDJTY2hvb2wgPC0gIlxcLkwyc2Nob29sJCIKbDJTY2hvb2xfdmFyaWFibGVzIDwtIGNvbG5hbWVzKGFsbClbZ3JlcChsMlNjaG9vbCxjb2xuYW1lcyhhbGwpKV0KCmdncGxvdChhbGwsYWVzKHg9TDEsZmlsbD1Db250ZXh0KSkgKyBnZW9tX2JhcigpICsgY29vcmRfZmxpcCgpICsgZ2d0aXRsZSgiRmlyc3QgTGFuZ3VhZ2UiKSArIGxhYnMoeT0iTi4gb2YgcGFydGljaXBhbnRzIix4PSIiKSArIHRoZW1lX2J3KCkKCnRhYmxlKGFsbCRMMSxhbGwkQ29udGV4dCkKCnRhYmxlKGFsbCRkZWdyZWUsYWxsJEwxKQpgYGAKCi0gQ2hlY2sgZm9yIEwxIGJ1dCB3ZSBkZWNpZGVkIG5vdCB0byBmaWx0ZXIgZm9yIGl0CgpgYGB7cn0KI0ZpbHRlciBieSBMMQoKbmMgPC0gbmFtZXModGFibGUoYWxsJENvbnRleHQpKQp0YWJsZShhbGwkQ29udGV4dCkKbDFfZmlsdGVyIDwtIGFsbFsoYWxsJENvbnRleHQgPT0gbmNbMV0gJiAoYWxsJEwxID09ICJHZXJtYW4iIHwgYWxsJEwxID09ICJHZXJtYW4gYW5kIEVuZ2xpc2giKSkgfCAKICAgICAgICAgICAgICAgICAgICAoYWxsJENvbnRleHQgPT0gbmNbMl0gJiAoYWxsJEwxID09ICJJdGFsaWFuIikpIHwgCiAgICAgICAgICAgICAgICAgICAgKGFsbCRDb250ZXh0ID09IG5jWzNdICYgKGFsbCRMMSA9PSAiRW5nbGlzaCIgfCBhbGwkTDEgPT0gIkVuZ2xpc2ggYW5kIER1dGNoIiB8IGFsbCRMMSA9PSAiR2VybWFuIGFuZCBFbmdsaXNoIikpIHwKICAgICAgICAgICAgICAgICAgICAoYWxsJENvbnRleHQgPT0gbmNbNF0gJiAoYWxsJEwxID09ICJFbmdsaXNoIiB8IGFsbCRMMSA9PSAiRW5nbGlzaCBhbmQgRHV0Y2giIHwgYWxsJEwxID09ICJHZXJtYW4gYW5kIEVuZ2xpc2giKSksXQoKCiNhbGwgPC0gbDFfZmlsdGVyCgojIGRvIG5vdCBmaWx0ZXIgZm9yIEwxCmFsbCA8LSBhbGwKCiMgc3Vic2V0IGRlbW9ncmFwaGljcwpkZW1vIDwtIHN1YnNldChhbGwsc2VsZWN0PWMoIlJlc3AuSUQiLGRlbW9ncmFwaGljc192YXIsbDJTY2hvb2xfdmFyaWFibGVzKSkKCiMgTnVtZXJpIGZpbmFsaQp0YWJsZShsMV9maWx0ZXIkQ29udGV4dCkKdGFibGUoYWxsJENvbnRleHQpCgpgYGAKCi0gRmlsdGVyIG1pc3NpbmcgdmFsdWU6CiAgLSBGaWx0ZXIgcGFydGljaXBhbnRzIHdobyBkaWRuJ3QgcHV0IHRoZSBkZWdyZWUKICAtIHdlIGRvbid0IGNhcmUgYWJvdXQgc3BlYWsub3RoZXIuTDIgYW5kIHN0dWR5Lm90aGVyLkwyCgpgYGB7cn0KbWlzc2luZ19ieVNhbXBsZSA8LSByb3dTdW1zKGlzLm5hKGRlbW8pKQpuYW1lcyhtaXNzaW5nX2J5U2FtcGxlKSA8LSBkZW1vJFJlc3AuSUQKbWlzc2luZ19ieVZhciA8LSBjb2xTdW1zKGlzLm5hKGRlbW8pKQpuYW1lcyhtaXNzaW5nX2J5VmFyKSA8LSBjb2xuYW1lcyhkZW1vKQoKYmFycGxvdChtaXNzaW5nX2J5U2FtcGxlKQpkIDwtIGRhdGEuZnJhbWUobWlzcz1taXNzaW5nX2J5VmFyKQpkJHZhcklEIDwtIHJvd25hbWVzKGQpCmdncGxvdChkYXRhPWQsYWVzKHg9dmFySUQseT1taXNzKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgdGhlbWVfYncoKSArdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgCgoKZGVtb19taXNzaW5nIDwtIGRlbW8gJT4lIGdyb3VwX2J5KENvbnRleHQpICU+JSBzdW1tYXJpc2Uocm9sZUwyLmRlZ3JlZV9uYSA9IHN1bShpcy5uYShyb2xlTDIuZGVncmVlKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEwyLlZDRV9uYSA9IHN1bShpcy5uYShMMi5WQ0UpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3RoZXI1Lm90aGVyLndheXNfbmE9c3VtKGlzLm5hKG90aGVyNS5vdGhlci53YXlzICkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmkxLnllYXJfbmEgPSBzdW0oaXMubmEodW5pMS55ZWFyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW1hcnkxLkwyc2Nob29sX25hPXN1bShpcy5uYShwcmltYXJ5MS5MMnNjaG9vbCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDTFMzLkwyc2Nob29sX25hID0gc3VtKGlzLm5hKENMUzMuTDJzY2hvb2wpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVlNMNC5MMnNjaG9vbF9uYT1zdW0oaXMubmEoVlNMNC5MMnNjaG9vbCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWdyZWUgPSBzdW0oaXMubmEoZGVncmVlKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjaG9vTDJjb3VudHJ5NS5MMnNjaG9vbF9uYT1zdW0oaXMubmEoc2Nob29MMmNvdW50cnk1Lkwyc2Nob29sKSkpCgojIFdlIGRvIG5vdCBmaWx0ZXIgZm9yIHNwZWFrLm90aGVyLkwyIG9yIHN0dWR5Lm90aGVyLkwyCgojZGVtb1tpcy5uYShkZW1vJHNwZWFrLm90aGVyLkwyKSxdCiMgdGVuaWFtbwojZGVtb1tpcy5uYShkZW1vJHN0dWR5Lm90aGVyLkwyKSxdCm1pc3NpbmdfYnlTYW1wbGVbbmFtZXMobWlzc2luZ19ieVNhbXBsZSkgPT0gIjUxNjY4NjE1ODEiXQojZGVtb1tpcy5uYShkZW1vJHllYXIuc3R1ZHlMMiksXQptaXNzaW5nX2J5U2FtcGxlW25hbWVzKG1pc3NpbmdfYnlTYW1wbGUpID09ICI1Mzc4Nzk4Nzg3Il0KCiMgcmVtb3ZlIE5BIGZyb20gZGVncmVlCiN0YWJsZShkZW1vJGRlZ3JlZSx1c2VOQSA9ICJhbHdheXMiKQojIFJlbW92ZSBwZW9wbGUKYWxsIDwtIGFsbFshaXMubmEoYWxsJGRlZ3JlZSksXQpgYGAKCiMjIFN0YXRzIGFib3V0IGZpbHRlcmVkIGRhdGFzZXQKCmBgYHtyfQprYWJsZSh0YWJsZShhbGwkQ29udGV4dCkpCmthYmxlKHRhYmxlKGFsbCRzdHVkeS55ZWFyKSkKa2FibGUodGFibGUoYWxsJHllYXIuc3R1ZHlMMikpCmBgYAoKIyMgUmVjb2RlZCBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMKCmBgYHtyfQpyZWNvZGVkX2RlbV9yaWNoaSA8LSByZWFkX2V4Y2VsKCIwMi1kZXNjcmlwdGl2ZV9kYXRhLzIxIDAzIG1lcmdlZF9maWx0ZXJlZF9pbXB1dGVkTWVkaWFuX2xpa2VydE51bWJlci54bHN4IikKYGBgCgoKIyMgV3JpdGUgZmlsdGVyZWQgYW5kIG1lcmdlZCBkYXRhc2V0CgpgYGB7cn0Kd3JpdGUuY3N2KGFsbCxmaWxlLnBhdGgoIjAyLWRlc2NyaXB0aXZlX2RhdGEvY29udGV4dC1tZXJnZWRfZmlsdGVyZWQuY3N2IikpCmBgYAoKIyMgRGVzY3JpcHRpdmUgcGxvdHMgYW5kIHRhYmxlcwoKYGBge3Igc3BlYWsub3RoZXIuTDJfYmluYXJ5LG1lc3NhZ2U9RkFMU0V9CmFsbCRzcGVhay5vdGhlci5MMl9iaW5hcnkgPC0gaWZlbHNlKCFpcy5uYShhbGwkc3BlYWsub3RoZXIuTDIpICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIShhbGwkc3BlYWsub3RoZXIuTDIgJWluJSBjKCJZZXMiLCJObyIpKSwiWWVzIixhcy5jaGFyYWN0ZXIoYWxsJHNwZWFrLm90aGVyLkwyKSkKCgprYWJsZSh0YWJsZShhbGwkc3BlYWsub3RoZXIuTDJfYmluYXJ5LGFsbCRDb250ZXh0LHVzZU5BID0gImFsd2F5cyIpKQoKYGBgCgotIEFnZQoKYGBge3IgYWdlX2J5X2NvbnRleHQsbWVzc2FnZT1GQUxTRX0KdGFiQWdlIDwtIHQodGFibGUoYWxsJEFnZSxhbGwkQ29udGV4dCkpCmdnZGYgPC0gZGF0YS5mcmFtZShBZ2UgPSByZXAoY29sbmFtZXModGFiQWdlKSxlYWNoPTQpWyEoYXMubnVtZXJpYyh0YWJBZ2UpID09IDApXSwKICBOLlBhcnRpY2lwYW50cyA9IGFzLm51bWVyaWModGFiQWdlKVshKGFzLm51bWVyaWModGFiQWdlKSA9PSAwKV0sCiAgQ29udGV4dCA9IHJlcChyb3duYW1lcyh0YWJBZ2UpLHRpbWVzPTMpWyEoYXMubnVtZXJpYyh0YWJBZ2UpID09IDApXSkKCmdncGxvdChnZ2RmLGFlcyh4PUFnZSx5PU4uUGFydGljaXBhbnRzLGZpbGw9Q29udGV4dCkpICsgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIixjb2xvdXI9IndoaXRlIixzdGF0PSJpZGVudGl0eSIpICArIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsOTAsMTApLGxpbWl0cz1jKDAsOTApKSArIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKCJQYXJ0aWNpcGFudHMgYnkgYWdlIikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IE4uUGFydGljaXBhbnRzKSwgaGp1c3Q9MC41LCB2anVzdD0tMC4yNSwgc2l6ZSA9IDIuNSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpKSAKCmBgYAoKYGBge3IgZ2VuZGVyX2J5X2NvbnRleHQsbWVzc2FnZT1GQUxTRX0KIyBhZGQgbnVtYmVycyBvbiB0aGUgYmFyCgp0YWJBZ2UgPC0gdCh0YWJsZShhbGwkR2VuZGVyLGFsbCRDb250ZXh0KSkKZ2dkZiA8LSBkYXRhLmZyYW1lKEdlbmRlciA9IHJlcChjb2xuYW1lcyh0YWJBZ2UpLGVhY2g9NClbIShhcy5udW1lcmljKHRhYkFnZSkgPT0gMCldLAogIE4uUGFydGljaXBhbnRzID0gYXMubnVtZXJpYyh0YWJBZ2UpWyEoYXMubnVtZXJpYyh0YWJBZ2UpID09IDApXSwKICBDb250ZXh0ID0gcmVwKHJvd25hbWVzKHRhYkFnZSksdGltZXM9MylbIShhcy5udW1lcmljKHRhYkFnZSkgPT0gMCldKQoKCmdncGxvdChnZ2RmLGFlcyh4PUdlbmRlcix5PU4uUGFydGljaXBhbnRzLGZpbGw9Q29udGV4dCkpICsgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIixjb2xvdXI9IndoaXRlIixzdGF0PSJpZGVudGl0eSIpICArIGxhYnMoeT0iTiBwYXJ0aWNpcGFudHMiKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsOTAsMTApLGxpbWl0cz1jKDAsOTApKSArIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKCJQYXJ0aWNpcGFudHMgYnkgZ2VuZGVyIikrICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTi5QYXJ0aWNpcGFudHMpLCBoanVzdD0wLjUsIHZqdXN0PS0wLjI1LCBzaXplID0gMi41LHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSkpIAoKYGBgCgpgYGB7ciBvcmlnbnNfYnlfY29udGV4dCxtZXNzYWdlPUZBTFNFfQojIGFkZCBudW1iZXJzIG9uIHRoZSBiYXIKdGFiQWdlIDwtIHQodGFibGUoYWxsJG9yaWdpbnMsYWxsJENvbnRleHQpKQpnZ3Bsb3QoYWxsLGFlcyh4PW9yaWdpbnMsZmlsbD1Db250ZXh0KSkgKyBnZW9tX2Jhcihwb3NpdGlvbj0iZG9kZ2UiLGNvbG91cj0id2hpdGUiKSArIGdndGl0bGUoIk9yaWdpbnMgYnkgY29udGV4dCIpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCw5MCwxMCksbGltaXRzPWMoMCw5MCkpICsgdGhlbWVfYncoKSArIGRyYXdfZ3JvYih0YWJsZUdyb2IodGFiQWdlKSwgeD0yLCB5PTYwLCB3aWR0aD0wLjMsIGhlaWdodD0wLjQpICsgZ2d0aXRsZSgiUGFydGljaXBhbnRzIGJ5IG9yaWdpbnMiKQp0YWJBZ2UKYGBgCgotIHByb2ZpY2llbmN5CgpgYGB7ciBwcm9maWNpZW5jeV9ieV9jb250ZXh0LG1lc3NhZ2U9RkFMU0V9CnRhYkFnZSA8LSB0KHRhYmxlKGFsbCRwcm9mLGFsbCRDb250ZXh0KSkKZ2dwbG90KGFsbCxhZXMoeD1Db250ZXh0LGZpbGw9cHJvZikpICsgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIixjb2xvdXI9IndoaXRlIikgKyBnZ3RpdGxlKCJQcm9maWNpZW5jeSBieSBjb250ZXh0IikgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDkwLDEwKSxsaW1pdHM9YygwLDkwKSkgKyB0aGVtZV9idygpICsgZHJhd19ncm9iKHRhYmxlR3JvYih0YWJBZ2UpLCB4PTIsIHk9ODAsIHdpZHRoPTAuMywgaGVpZ2h0PTAuNCkKdGFiQWdlCmBgYAoKLSBMMi5WQ0UKCmBgYHtyIEwyVkNFX2J5X2NvbnRleHQsbWVzc2FnZT1GQUxTRX0KdGFiQWdlIDwtIHQodGFibGUoYWxsW2FsbCRDb250ZXh0ICE9ICJFbmdsaXNoIGluIEdlcm1hbnkiICYgYWxsJENvbnRleHQgIT0gIkVuZ2xpc2ggaW4gSXRhbHkiLCJMMi5WQ0UiXSxhbGxbYWxsJENvbnRleHQgIT0gIkVuZ2xpc2ggaW4gR2VybWFueSIgJiBhbGwkQ29udGV4dCAhPSAiRW5nbGlzaCBpbiBJdGFseSIsJ0NvbnRleHQnXSx1c2VOQSA9ICJhbHdheXMiKSkKdGFiQWdlIDwtIHRhYkFnZVstMyxdCgpnZ3Bsb3QoYWxsW2FsbCRDb250ZXh0ICE9ICJFbmdsaXNoIGluIEdlcm1hbnkiICYgYWxsJENvbnRleHQgIT0gIkVuZ2xpc2ggaW4gSXRhbHkiLF0sYWVzKHg9Q29udGV4dCxmaWxsPUwyLlZDRSkpICsgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIixjb2xvdXI9IndoaXRlIikgKyBnZ3RpdGxlKCJMMi5WQ0UgYnkgY29udGV4dCIpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCw5MCwxMCksbGltaXRzPWMoMCw5MCkpICsgdGhlbWVfYncoKSArIGRyYXdfZ3JvYih0YWJsZUdyb2IodGFiQWdlKSwgeD0yLCB5PTgwLCB3aWR0aD0wLjMsIGhlaWdodD0wLjQpCmBgYAoKLSBkYSBtZXR0ZXJlIGEgcG9zdG8gY29uIFJpY2hpCgpgYGB7ciB5ZWFyLnN0dWR5TDJfRXVyb3BlYW5fY29udGV4dCxtZXNzYWdlPUZBTFNFfQojIHllYXIgc3R1ZHkgTDIKdGFibGUoYWxsJHllYXIuc3R1ZHlMMixhbGwkb3RoZXIueWVhci5zdHVkeUwyLnJpY2hpKQoKYWxsJHllYXIuc3R1ZHlMMiA8LSBpZmVsc2UoYWxsJHllYXIuc3R1ZHlMMiA9PSAiT3RoZXIiLGFsbCRvdGhlci55ZWFyLnN0dWR5TDIucmljaGksYWxsJHllYXIuc3R1ZHlMMiApCgojIEV1cm9wZWFuIGNvbnRleHQKZ2dwbG90KGFsbFthbGwkQ29udGV4dCA9PSAiRW5nbGlzaCBpbiBHZXJtYW55IiB8IGFsbCRDb250ZXh0ID09ICJFbmdsaXNoIGluIEl0YWx5IixdLGFlcyh4PWRlZ3JlZSxmaWxsPXllYXIuc3R1ZHlMMikpICsgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIixjb2xvdXI9IndoaXRlIikgKyB0aGVtZV9idygpICsgZ2d0aXRsZSgiRGVncmVlIGJ5IHN0dWR5IHllYXIgTDIsIGJ5IENvbnRleHQiKSArICBmYWNldF9ncmlkKH5Db250ZXh0LHNjYWxlcz0iZnJlZSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyBsYWJzKHkgPSAiTiBwYXJ0aWNpcGFudHMiLCB4ID0gImRlZ3JlZSIpCmBgYAoKLSBEZWdyZWUgb2YgZW5yb2xtZW50CgpgYGB7ciBkZWdyZWVfYnlfY29udGV4dCxtZXNzYWdlPUZBTFNFfQojIEF1c3RyYWxpYW4gY29udGV4dAp0YWJBZ2UgPC0gdCh0YWJsZShhbGxbYWxsJENvbnRleHQgPT0gIkl0YWxpYW4gaW4gQXVzdHJhbGlhIiB8IGFsbCRDb250ZXh0ID09ICJHZXJtYW4gaW4gQXVzdHJhbGlhIiwnZGVncmVlJ10sYWxsW2FsbCRDb250ZXh0ID09ICJJdGFsaWFuIGluIEF1c3RyYWxpYSIgfCBhbGwkQ29udGV4dCA9PSAiR2VybWFuIGluIEF1c3RyYWxpYSIsJ0NvbnRleHQnXSkpCmdncGxvdChhbGxbYWxsJENvbnRleHQgPT0gIkl0YWxpYW4gaW4gQXVzdHJhbGlhIiB8IGFsbCRDb250ZXh0ID09ICJHZXJtYW4gaW4gQXVzdHJhbGlhIixdLGFlcyh4PUNvbnRleHQsZmlsbD1kZWdyZWUpKSArIGdlb21fYmFyKHBvc2l0aW9uPSJkb2RnZSIsY29sb3VyPSJ3aGl0ZSIpICsgdGhlbWVfYncoKSArIGdndGl0bGUoIkRlZ3JlZSBpbiBBdXN0cmFsaWFuIENvbnRleHRzIikgKyBkcmF3X2dyb2IodGFibGVHcm9iKHRhYkFnZSksIHg9MS4sIHk9NDAsIHdpZHRoPTAuMywgaGVpZ2h0PTAuNCkKdGFiQWdlCmBgYAoKYGBge3IgeWVhci5zdHVkeUwyX0F1c3RyYWxpYW5fY29udGV4dCxtZXNzYWdlPUZBTFNFfQojIEF1c3RyYWxpYW4gY29udGV4dAp0YWJBZ2UgPC0gdCh0YWJsZShhbGxbYWxsJENvbnRleHQgPT0gIkVuZ2xpc2ggaW4gSXRhbHkiIHwgYWxsJENvbnRleHQgPT0gIkVuZ2xpc2ggaW4gR2VybWFueSIsJ2RlZ3JlZSddLGFsbFthbGwkQ29udGV4dCA9PSAiRW5nbGlzaCBpbiBJdGFseSIgfCBhbGwkQ29udGV4dCA9PSAiRW5nbGlzaCBpbiBHZXJtYW55IiwnQ29udGV4dCddKSkKCmdncGxvdChhbGxbYWxsJENvbnRleHQgPT0gIkVuZ2xpc2ggaW4gSXRhbHkiIHwgYWxsJENvbnRleHQgPT0gIkVuZ2xpc2ggaW4gR2VybWFueSIsXSxhZXMoeD1Db250ZXh0LGZpbGw9ZGVncmVlKSkgKyBnZW9tX2Jhcihwb3NpdGlvbj0iZG9kZ2UiLGNvbG91cj0id2hpdGUiKSArIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKCJEZWdyZWUgaW4gRXVyb3BlYW4gQ29udGV4dHMiKQoKdGFiQWdlCmBgYAoKCiMgQXVzdHJhbGlhbiBjb250ZXh0IHNwY2lmaWMgdmFyaWFibGVzIAoKYGBge3J9CmthYmxlKHRhYmxlKGFsbCRyZWNvbm5lY3QuY29tbSxhbGwkQ29udGV4dCkpCmthYmxlKHRhYmxlKGFsbCRzcGVha2Vyc21lbGIuY29tbSxhbGwkQ29udGV4dCkpCmthYmxlKHRhYmxlKGFsbCRjb21lY2xvc2VyLmNvbW0sYWxsJENvbnRleHQpKQpgYGAKCgpcY2xlYXJwYWdlCgojIExpa2VydCBzY2FsZXMKCmBgYHtyIGluY2x1ZGU9RkFMU0UsbWVzc2FnZT1GQUxTRX0KbGlrZXJ0X2dyZXAgPC0gIlxcLmlkJHxcXC5vdWdodCR8XFwuaW50ciR8XFwuaW5zdHJ1JHxcXC5pbnRlZ3IkfFxcLnByb2YkfFxcLnBvc3QkfFxcLmNvbW0kfF5uZWNlc3NpdHkkfF5lZHVjYXRlZCQiCgojIGFsbApsaWtlcnRfdmFyaWFibGVzX2FsbCA8LSBjb2xuYW1lcyhhbGwpW2dyZXAobGlrZXJ0X2dyZXAsY29sbmFtZXMoYWxsKSldCmxpa2VydF92YXJpYWJsZXNfYWxsCmxpa2VydF92YXJpYWJsZXNfYWxsIDwtIGxpa2VydF92YXJpYWJsZXNfYWxsWyEobGlrZXJ0X3ZhcmlhYmxlc19hbGwgJWluJSAib3RoZXIucHJvZiIpXQoKYGBgCgotICoqQ29udmVydCBMaWtlcnQgc2NhbGVzIHRvIG51bWJlcnMqKgoKYGBge3IgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MTV9Cgpjb252ZXJ0VG9OdW1iZXIgPC0gZnVuY3Rpb24oY29sdW1uKXsKICBjb2x1bW4gPC0gZmFjdG9yKGNvbHVtbixsZXZlbHMgPSBjKCJTdHJvbmdseSBkaXNhZ3JlZSIsIkRpc2FncmVlIiwiTm90IHN1cmUiLCJBZ3JlZSIsIlN0cm9uZ2x5IGFncmVlIikpCiAgY29sdW1uX251bWJlciA8LSBhcy5udW1lcmljKGNvbHVtbikKICByZXR1cm4oY29sdW1uX251bWJlcikKfQoKdGFibGUoYWxsJENvbnRleHQpCnRhYmxlKGFsbCRzdHVkeS55ZWFyKQoKY29udmVydF9saWtlcnQgPC0gZGF0YS5mcmFtZShhcHBseShzdWJzZXQoYWxsLHNlbGVjdD1saWtlcnRfdmFyaWFibGVzX2FsbCksMixjb252ZXJ0VG9OdW1iZXIpKQpjb2xuYW1lcyhjb252ZXJ0X2xpa2VydCkgPC0gcGFzdGUwKGNvbG5hbWVzKGNvbnZlcnRfbGlrZXJ0KSwiMSIpCgpsaWtlcnRfdmFyaWFibGVzMSA8LSBwYXN0ZTAobGlrZXJ0X3ZhcmlhYmxlc19hbGwsIjEiKQoKIyBqb2luIHRoZSBjb252ZXJ0ZWQgdmFyaWFibGVzIHRvIHRoZSBmaWx0ZXJlZCBkYXRhc2V0CmZpbHRlcmVkX2NvbnYgPC0gY2JpbmQoYWxsLGNvbnZlcnRfbGlrZXJ0KQoKdGFibGUoZmlsdGVyZWRfY29udlssbGlrZXJ0X3ZhcmlhYmxlc19hbGxbNF1dLGZpbHRlcmVkX2NvbnZbLGxpa2VydF92YXJpYWJsZXMxWzRdXSx1c2VOQSA9ICJhbHdheXMiKQoKd3JpdGUuY3N2KGZpbHRlcmVkX2NvbnYsIjAyLWRlc2NyaXB0aXZlX2RhdGEvbWVyZ2VkX2ZpbHRlcmVkX2xpa2VydE51bWJlci5jc3YiLHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIEltcHV0ZSBtaXNzaW5nIHZhbHVlcyAtIFVzaW5nIG1lZGlhbiB2YWx1ZXMKClRoZSBtaXNzaW5nIHZhbHVlcyBhcHBlYXJzIHRvIGJlIGF0IHJhbmRvbSBhbmQgdGhlcmUgYXJlIG1heCB0d28gbWlzc2luZyB2YWx1ZXMgaW4gb25lIHZhcmlhYmxlIChzZWUgcGxvdHMgYmVsb3cpLiBJbiBvcmRlciBub3QgdG8gbG9vc2UgMTIgcGFydGljaXBhbnRzIHdoaWxlIGRvaW5nIHRoZSBmYWN0b3IgYW5hbHlzaXMgYWNyb3NzIGNvbnRleHRzIGl0IGlzIHByZWZlcmFibGUgdG8gaW1wdXRlIHRoZSAxMiBtaXNzaW5nIHZhbHVlcy4gCgpgYGB7cn0KYWxsIDwtIGZpbHRlcmVkX2NvbnYKCiMgSXRlbXMgdG8gdXNlIGZvciBmYWN0b3IgYW5hbHlzaXMgOiBpdGVtcyBzaGFyZWQgYmV0d2VlbiBjb250ZXh0cwojIGl0ZW1zIHRvIGJlIHVzZWQgZm9yIHRoZSBGQQoKdXNhYmxlX2l0ZW1zIDwtIGxpa2VydF92YXJpYWJsZXMxWyEobGlrZXJ0X3ZhcmlhYmxlczEgJWluJSBjKCJuZWNlc3NpdHkxIiwiZWR1Y2F0ZWQxIiwicmVjb25uZWN0LmNvbW0xIiwgInNwZWFrZXJzbWVsYi5jb21tMSIsICJjb21lY2xvc2VyLmNvbW0xIikpXQpgYGAKCgpgYGB7cn0Kcm93bmFtZXMoYWxsKSA8LSBhbGwkUmVzcC5JRAp1c2FibGVfZGF0YV9jb250ZXh0IDwtIGFsbFssYyh1c2FibGVfaXRlbXMsIkNvbnRleHQiKV0KZGF0X25vTkEgPC0gdXNhYmxlX2RhdGFfY29udGV4dFtyb3dTdW1zKGlzLm5hKHVzYWJsZV9kYXRhX2NvbnRleHQpKSA9PSAwLF0KYWxsX25vTkEgPC0gYWxsW3Jvd1N1bXMoaXMubmEodXNhYmxlX2RhdGFfY29udGV4dCkpID09IDAsXQp0YWJsZShyb3dTdW1zKGlzLm5hKHVzYWJsZV9kYXRhX2NvbnRleHQpKSkKIyBQYXJ0aWNpcGFudHMgd2l0aCBOQSB0byByZW1vdmUKdGFibGUocm93U3Vtcyhpcy5uYSh1c2FibGVfZGF0YV9jb250ZXh0KSksdXNhYmxlX2RhdGFfY29udGV4dCRDb250ZXh0LHVzZU5BID0gImFsd2F5cyIpCgojIFZhcmlhYmxlIG1pc3NpbmcgdmFsdWVzCnRhYmxlKGNvbFN1bXMoaXMubmEodXNhYmxlX2RhdGFfY29udGV4dCkpKQp0YWJsZShyb3dTdW1zKGlzLm5hKHVzYWJsZV9kYXRhX2NvbnRleHQpKSx1c2FibGVfZGF0YV9jb250ZXh0JENvbnRleHQsdXNlTkEgPSAiYWx3YXlzIikKCiMgY2hlY2sgd2hhdCB0byB1c2UgdG8gaW1wdXRlCiMgaGF2ZSBhIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBtaXNzaW5nIHZhbHVlcwpsaWJyYXJ5KG1pY2UpCmxpYnJhcnkoVklNKQoKbWljZV9wbG90IDwtIGFnZ3IodXNhYmxlX2RhdGFfY29udGV4dFssdXNhYmxlX2l0ZW1zXSwgY29sPWMoJ25hdnlibHVlJywneWVsbG93JyksCiAgICAgICAgICAgICAgICAgICAgbnVtYmVycz1UUlVFLCBzb3J0VmFycz1UUlVFLAogICAgICAgICAgICAgICAgICAgIGxhYmVscz1uYW1lcyh1c2FibGVfZGF0YV9jb250ZXh0Wyx1c2FibGVfaXRlbXNdKSwgY2V4LmF4aXM9LjQsCiAgICAgICAgICAgICAgICAgICAgZ2FwPTEsIHlsYWI9YygiTWlzc2luZyBkYXRhIiwiUGF0dGVybiIpLGNleC5udW1iZXJzPTAuNSkKCiMgSW1wdXRpbmcgdXNpbmcgbWVkaWFuCmxpYnJhcnkoSG1pc2MpCmltcHV0ZWRNZWRpYW4gPC0gdXNhYmxlX2RhdGFfY29udGV4dAoKaW1wdXRlZE1lZGlhbiRnbG9iYWxhY2Nlc3MucG9zdDEgPC0gd2l0aChpbXB1dGVkTWVkaWFuWyx1c2FibGVfaXRlbXNdLCBpbXB1dGUoZ2xvYmFsYWNjZXNzLnBvc3QxLCBtZWRpYW4pKQppbXB1dGVkTWVkaWFuJGNpdGl6ZW4ucG9zdDEgPC0gd2l0aChpbXB1dGVkTWVkaWFuWyx1c2FibGVfaXRlbXNdLCBpbXB1dGUoY2l0aXplbi5wb3N0MSwgbWVkaWFuKSkKaW1wdXRlZE1lZGlhbiRtb25leS5pbnN0cnUxIDwtIHdpdGgoaW1wdXRlZE1lZGlhblssdXNhYmxlX2l0ZW1zXSwgaW1wdXRlKG1vbmV5Lmluc3RydTEsIG1lZGlhbikpCmltcHV0ZWRNZWRpYW4ka25vd2xlZGdlLmluc3RydTEgPC0gd2l0aChpbXB1dGVkTWVkaWFuWyx1c2FibGVfaXRlbXNdLCBpbXB1dGUoa25vd2xlZGdlLmluc3RydTEsIG1lZGlhbikpCmltcHV0ZWRNZWRpYW4kbGlmZS5pbnRyMSA8LSB3aXRoKGltcHV0ZWRNZWRpYW5bLHVzYWJsZV9pdGVtc10sIGltcHV0ZShsaWZlLmludHIxLCBtZWRpYW4pKQppbXB1dGVkTWVkaWFuJHRpbWUuaW50ZWdyMSA8LSB3aXRoKGltcHV0ZWRNZWRpYW5bLHVzYWJsZV9pdGVtc10sIGltcHV0ZSh0aW1lLmludGVncjEsIG1lZGlhbikpCmltcHV0ZWRNZWRpYW4kZXhwZWN0Lm91Z2h0MSA8LSB3aXRoKGltcHV0ZWRNZWRpYW5bLHVzYWJsZV9pdGVtc10sIGltcHV0ZShleHBlY3Qub3VnaHQxLCBtZWRpYW4pKQppbXB1dGVkTWVkaWFuJGpvYi5pbnN0cnUxIDwtIHdpdGgoaW1wdXRlZE1lZGlhblssdXNhYmxlX2l0ZW1zXSwgaW1wdXRlKGpvYi5pbnN0cnUxLCBtZWRpYW4pKQppbXB1dGVkTWVkaWFuJGNhcmVlci5pbnN0cnUxIDwtIHdpdGgoaW1wdXRlZE1lZGlhblssdXNhYmxlX2l0ZW1zXSwgaW1wdXRlKGNhcmVlci5pbnN0cnUxLCBtZWRpYW4pKQppbXB1dGVkTWVkaWFuJG1lZXRpbmcuaW50ZWdyMSA8LSB3aXRoKGltcHV0ZWRNZWRpYW5bLHVzYWJsZV9pdGVtc10sIGltcHV0ZShtZWV0aW5nLmludGVncjEsIG1lZGlhbikpCmltcHV0ZWRNZWRpYW4kaW50ZXJhY3QucG9zdDEgPC0gd2l0aChpbXB1dGVkTWVkaWFuWyx1c2FibGVfaXRlbXNdLCBpbXB1dGUoaW50ZXJhY3QucG9zdDEsIG1lZGlhbikpCgojIGNoZWNrIGJlZm9yZSBhZnRlcgp0YWJsZShpbXB1dGVkTWVkaWFuJHRpbWUuaW50ZWdyMSkKdGFibGUodXNhYmxlX2RhdGFfY29udGV4dCR0aW1lLmludGVncjEpCgp0YWJsZShpbXB1dGVkTWVkaWFuJGxpZmUuaW50cjEpCnRhYmxlKHVzYWJsZV9kYXRhX2NvbnRleHQkbGlmZS5pbnRyMSkKCnRhYmxlKGltcHV0ZWRNZWRpYW4ka25vd2xlZGdlLmluc3RydTEpCnRhYmxlKHVzYWJsZV9kYXRhX2NvbnRleHQka25vd2xlZGdlLmluc3RydTEpCgp0YWJsZShpbXB1dGVkTWVkaWFuJG1vbmV5Lmluc3RydTEpCnRhYmxlKHVzYWJsZV9kYXRhX2NvbnRleHQkbW9uZXkuaW5zdHJ1MSkKCnRhYmxlKGltcHV0ZWRNZWRpYW4kY2l0aXplbi5wb3N0MSkKdGFibGUodXNhYmxlX2RhdGFfY29udGV4dCRjaXRpemVuLnBvc3QxKQoKdGFibGUoaW1wdXRlZE1lZGlhbiRnbG9iYWxhY2Nlc3MucG9zdDEpCnRhYmxlKHVzYWJsZV9kYXRhX2NvbnRleHQkZ2xvYmFsYWNjZXNzLnBvc3QxKQoKCnRhYmxlKGltcHV0ZWRNZWRpYW4kZXhwZWN0Lm91Z2h0MSkKdGFibGUodXNhYmxlX2RhdGFfY29udGV4dCRleHBlY3Qub3VnaHQxKQoKdGFibGUoaW1wdXRlZE1lZGlhbiRqb2IuaW5zdHJ1MSkKdGFibGUodXNhYmxlX2RhdGFfY29udGV4dCRqb2IuaW5zdHJ1MSkKCnRhYmxlKGltcHV0ZWRNZWRpYW4kY2FyZWVyLmluc3RydTEpCnRhYmxlKHVzYWJsZV9kYXRhX2NvbnRleHQkY2FyZWVyLmluc3RydTEpCgp0YWJsZShpbXB1dGVkTWVkaWFuJG1lZXRpbmcuaW50ZWdyMSkKdGFibGUodXNhYmxlX2RhdGFfY29udGV4dCRtZWV0aW5nLmludGVncjEpCgp0YWJsZShpbXB1dGVkTWVkaWFuJGludGVyYWN0LnBvc3QxKQp0YWJsZSh1c2FibGVfZGF0YV9jb250ZXh0JGludGVyYWN0LnBvc3QxKQoKCmBgYAoKLSBTdWJzdGl0dXRlIGltcHV0ZWQgZGF0YSBmb3IgdGhlIGNvbW1vbiB2YXJpYWJsZXMgdG8gYmUgdXNlZCBpbiB0aGUgRmFjdG9yIEFuYWx5c2lzCgpgYGB7cn0KYWxsIDwtIGFsbFssIShjb2xuYW1lcyhhbGwpICVpbiUgdXNhYmxlX2l0ZW1zKV0KaW1wdXRlZE1lZGlhbiRDb250ZXh0IDwtIE5VTEwKc3VtKCEoY29sbmFtZXMoaW1wdXRlZE1lZGlhbikgJWluJSB1c2FibGVfaXRlbXMpKQphbGwgPC0gY2JpbmQoYWxsLGltcHV0ZWRNZWRpYW5bbWF0Y2gocm93bmFtZXMoaW1wdXRlZE1lZGlhbiksYWxsJFJlc3AuSUQpLF0pCmBgYAoKKipBZGQgc29tZSB1cGRhdGVzIHRoYXQgUmljaGkgZGlkIGluIERhdGUgN3RoIEp1bmUgMjAxOCoqCgpgYGB7ciBldmFsPUZBTFNFfQpPdGhlcl93YXlzX2FuZF9kZWdyZWVfcm9sZV93aXRoX3Jlc3BvbmRlbnRfSURzIDwtIHJlYWRfZXhjZWwoIk90aGVyLXdheXMtYW5kLWRlZ3JlZS1yb2xlLXdpdGgtcmVzcG9uZGVudC1JRHMueGxzeCIpCnN1bShPdGhlcl93YXlzX2FuZF9kZWdyZWVfcm9sZV93aXRoX3Jlc3BvbmRlbnRfSURzJFJlc3AuSUQgIT0gT3RoZXJfd2F5c19hbmRfZGVncmVlX3JvbGVfd2l0aF9yZXNwb25kZW50X0lEcyRSZXNwLklEX18xKQojIHRvIHJlcGxhY2UgCiMgbWF0Y2ggZm9yIHRoZSBOQSBkZWdyZWUucm9sZQoKbWF0Y2hfdXBkYXRlcyA8LSBtYXRjaChhbGwkUmVzcC5JRCxPdGhlcl93YXlzX2FuZF9kZWdyZWVfcm9sZV93aXRoX3Jlc3BvbmRlbnRfSURzJFJlc3AuSUQpCmFsbCRwcml2YXRlLmxlc3NvbnMxLm90aGVyLndheXNbbWF0Y2hfdXBkYXRlc10gPC0gT3RoZXJfd2F5c19hbmRfZGVncmVlX3JvbGVfd2l0aF9yZXNwb25kZW50X0lEcyRwcml2YXRlLmxlc3NvbnMxLm90aGVyLndheXMKYWxsJHN0dWR5LmhvbGlkYXkyLm90aGVyLndheXNbbWF0Y2hfdXBkYXRlc10gPC0gT3RoZXJfd2F5c19hbmRfZGVncmVlX3JvbGVfd2l0aF9yZXNwb25kZW50X0lEcyRzdHVkeS5ob2xpZGF5Mi5vdGhlci53YXlzCmFsbCR5ZWFyLnNlbS5hYnJvYWQzLm90aGVyLndheXNbbWF0Y2hfdXBkYXRlc10gPC0gT3RoZXJfd2F5c19hbmRfZGVncmVlX3JvbGVfd2l0aF9yZXNwb25kZW50X0lEcyR5ZWFyLnNlbS5hYnJvYWQzLm90aGVyLndheXMKYWxsJG9ubGluZS5jb3Vyc2U0Lm90aGVyLndheXNbbWF0Y2hfdXBkYXRlc10gPC0gT3RoZXJfd2F5c19hbmRfZGVncmVlX3JvbGVfd2l0aF9yZXNwb25kZW50X0lEcyRvbmxpbmUuY291cnNlNC5vdGhlci53YXlzCmFsbCRvdGhlcjUub3RoZXIud2F5c1ttYXRjaF91cGRhdGVzXSA8LSBPdGhlcl93YXlzX2FuZF9kZWdyZWVfcm9sZV93aXRoX3Jlc3BvbmRlbnRfSURzJG90aGVyNS5vdGhlci53YXlzCmFsbCRkZWdyZWUucm9sZVttYXRjaF91cGRhdGVzXSA8LSBPdGhlcl93YXlzX2FuZF9kZWdyZWVfcm9sZV93aXRoX3Jlc3BvbmRlbnRfSURzJGRlZ3JlZS5yb2xlCmBgYAoKIyMgU2F2ZSBpbXB1dGVkIGRhdGEKCmBgYHtyfQp3cml0ZS5jc3YoYWxsLCIwMi1kZXNjcmlwdGl2ZV9kYXRhL21lcmdlZF9maWx0ZXJlZF9pbXB1dGVkTWVkaWFuX2xpa2VydE51bWJlci5jc3YiLHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMgQmFycGxvdCBvZiBsaWtlcnQgdmFyaWFibGVzCgpgYGB7ciBmaWcud2lkdGg9MjAsZmlnLmhlaWdodD0yMH0KYWxsX21lbHQgPC0gbWVsdChhbGwsaWQudmFycyA9IGMoIlJlc3AuSUQiLCJHZW5kZXIiLCJBZ2UiLCJwcm9mIiwiQ29udGV4dCIsInN0dWR5LnllYXIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gbGlrZXJ0X3ZhcmlhYmxlczEpCgphbGxfbWVsdCR2YWx1ZSA8LSBmYWN0b3IoYWxsX21lbHQkdmFsdWUsbGV2ZWxzPWMoMSwyLDMsNCw1KSxsYWJlbHM9YygiU3Ryb25nbHkgZGlzYWdyZWUiLCJEaXNhZ3JlZSIsIk5vdCBzdXJlIiwiQWdyZWUiLCJTdHJvbmdseSBhZ3JlZSIpKQojIGRpbShhbGxfbWVsdCkKIyAzMjMqbGVuZ3RoKGxpa2VydF92YXJpYWJsZXMxKQoKYWxsX21lbHQgPC0gYWxsX21lbHQgJT4lIHNlcGFyYXRlKHZhcmlhYmxlLGludG89YygiaXRlbSIsInR5cGUiKSxzZXA9IlxcLiIscmVtb3ZlPUZBTFNFKQpnZ3Bsb3QoYWxsX21lbHQsYWVzKHg9dmFyaWFibGUsZmlsbD12YWx1ZSkpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLGNvbG91cj0iYmxhY2siKSArIAogIGZhY2V0X2dyaWQoQ29udGV4dH50eXBlLHNjYWxlcyA9ICJmcmVlIikrdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSxheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsgZ2d0aXRsZSgiRmlsdGVyZWQgZGF0YXNldCIpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNjYTAwMjAiLCIjZjRhNTgyIiwiI2ZmZmZiZiIsIiNhYmQ5ZTkiLCIjMmM3YmI2IiwiZ3JleSIpKQoKZmlsdF9zdW0gPC0gYWxsX21lbHQgJT4lIGdyb3VwX2J5KENvbnRleHQsdmFyaWFibGUsdHlwZSx2YWx1ZSkgJT4lIGRwbHlyOjpzdW1tYXJpc2UoTmdyb3VwPWxlbmd0aCh2YWx1ZSkpCmdncGxvdChmaWx0X3N1bSxhZXMoeD12YWx1ZSx5PU5ncm91cCxjb2xvdXI9Q29udGV4dCxncm91cD1pbnRlcmFjdGlvbih2YXJpYWJsZSwgQ29udGV4dCkpKSArIGdlb21fbGluZSgpICsgZ2VvbV9wb2ludCgpICsgZmFjZXRfd3JhcCh+dHlwZSxzY2FsZXMgPSAiZnJlZSIpK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpgYGAKCiMjIEJhcnBsb3Qgb2YgRWR1Y2F0ZWQgYW5kIE5lY2Vzc2l0eSBpbiB0aGUgQXVzdHJhbGlhbiBhbmQgRXVyb3BlYW4gQ29udGV4dHMKCi0gKipFZHVjYXRlZCoqCgpgYGB7cn0KIyBhZGQgbnVtYmVycyBvbiB0aGUgYmFyCmVkdWNhdGVkIDwtIGFsbFthbGwkQ29udGV4dCAlaW4lIGMoIkdlcm1hbiBpbiBBdXN0cmFsaWEiLCJJdGFsaWFuIGluIEF1c3RyYWxpYSIpLF0KdGFibGUoZWR1Y2F0ZWQkZWR1Y2F0ZWQxLGVkdWNhdGVkJENvbnRleHQsdXNlTkE9ImFsd2F5cyIpCmVkdWNhdGVkJGVkdWNhdGVkMSA8LSBmYWN0b3IoZWR1Y2F0ZWQkZWR1Y2F0ZWQxLGxldmVscyA9IGMoMSwyLDMsNCw1KSxsYWJlbHM9YygiU3Ryb25nbHkgZGlzYWdyZWUiLCJEaXNhZ3JlZSIsIk5vdCBzdXJlIiwiQWdyZWUiLCJTdHJvbmdseSBhZ3JlZSIpKSAKCnRhYkVkdSA8LSB0KHRhYmxlKGVkdWNhdGVkJGVkdWNhdGVkMSxlZHVjYXRlZCRDb250ZXh0KSkKZ2dkZiA8LSBkYXRhLmZyYW1lKEVkdWNhdGVkID0gcmVwKGNvbG5hbWVzKHRhYkVkdSksZWFjaD0yKSwKICBOLlBhcnRpY2lwYW50cyA9IGFzLm51bWVyaWModGFiRWR1KSwKICBDb250ZXh0ID0gcmVwKHJvd25hbWVzKHRhYkVkdSksdGltZXM9NSkpCgoKZ2dwbG90KGdnZGYsYWVzKHg9RWR1Y2F0ZWQseT1OLlBhcnRpY2lwYW50cyxmaWxsPUNvbnRleHQpKSArIGdlb21fYmFyKHBvc2l0aW9uPSJkb2RnZSIsY29sb3VyPSJ3aGl0ZSIsc3RhdD0iaWRlbnRpdHkiKSAgKyBsYWJzKHk9Ik4gcGFydGljaXBhbnRzIikgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDM1LDEwKSxsaW1pdHM9YygwLDM1KSkgKyB0aGVtZV9idygpICsgZ2d0aXRsZSgiRWR1Y2F0ZWQgYnkgQ29udGV4dCIpKyAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IE4uUGFydGljaXBhbnRzKSwgaGp1c3Q9MC41LCB2anVzdD0tMC4yNSwgc2l6ZSA9IDIuNSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpKSAKZ2dwbG90KGdnZGYsYWVzKHg9Q29udGV4dCx5PU4uUGFydGljaXBhbnRzLGZpbGw9RWR1Y2F0ZWQpKSArIGdlb21fYmFyKHBvc2l0aW9uPSJkb2RnZSIsY29sb3VyPSJ3aGl0ZSIsc3RhdD0iaWRlbnRpdHkiKSAgKyBsYWJzKHk9Ik4gcGFydGljaXBhbnRzIikgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDM1LDEwKSxsaW1pdHM9YygwLDM1KSkgKyB0aGVtZV9idygpICsgZ2d0aXRsZSgiRWR1Y2F0ZWQgYnkgQ29udGV4dCIpKyAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IE4uUGFydGljaXBhbnRzKSwgaGp1c3Q9MC41LCB2anVzdD0tMC4yNSwgc2l6ZSA9IDIuNSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpKSAKYGBgCgotICoqTmVjZXNzaXR5KioKCmBgYHtyfQojIGFkZCBudW1iZXJzIG9uIHRoZSBiYXIKbmVjZXNzaXR5IDwtIGFsbFthbGwkQ29udGV4dCAlaW4lIGMoIkVuZ2xpc2ggaW4gR2VybWFueSIsIkVuZ2xpc2ggaW4gSXRhbHkiKSxdCnRhYmxlKG5lY2Vzc2l0eSRuZWNlc3NpdHkxLG5lY2Vzc2l0eSRDb250ZXh0LHVzZU5BPSJhbHdheXMiKQpuZWNlc3NpdHkkbmVjZXNzaXR5MSA8LSBmYWN0b3IobmVjZXNzaXR5JG5lY2Vzc2l0eTEsbGV2ZWxzID0gYygxLDIsMyw0LDUpLGxhYmVscz1jKCJTdHJvbmdseSBkaXNhZ3JlZSIsIkRpc2FncmVlIiwiTm90IHN1cmUiLCJBZ3JlZSIsIlN0cm9uZ2x5IGFncmVlIikpIAoKdGFiTmVjIDwtIHQodGFibGUobmVjZXNzaXR5JG5lY2Vzc2l0eTEsbmVjZXNzaXR5JENvbnRleHQsdXNlTkEgPSAiYWx3YXlzIikpWy0zLF0KZ2dkZiA8LSBkYXRhLmZyYW1lKE5lY2Vzc2l0eSA9IHJlcChjb2xuYW1lcyh0YWJOZWMpLGVhY2g9MiksCiAgTi5QYXJ0aWNpcGFudHMgPSBhcy5udW1lcmljKHRhYk5lYyksCiAgQ29udGV4dCA9IHJlcChyb3duYW1lcyh0YWJOZWMpLHRpbWVzPTYpKQoKCmdncGxvdChnZ2RmLGFlcyh4PU5lY2Vzc2l0eSx5PU4uUGFydGljaXBhbnRzLGZpbGw9Q29udGV4dCkpICsgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIixjb2xvdXI9IndoaXRlIixzdGF0PSJpZGVudGl0eSIpICArIGxhYnMoeT0iTiBwYXJ0aWNpcGFudHMiKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsNDAsMTApLGxpbWl0cz1jKDAsNDApKSArIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKCJOZWNlc3NpdHkgYnkgQ29udGV4dCIpKyAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IE4uUGFydGljaXBhbnRzKSwgaGp1c3Q9MC41LCB2anVzdD0tMC4yNSwgc2l6ZSA9IDIuNSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpKSAKZ2dwbG90KGdnZGYsYWVzKHg9Q29udGV4dCx5PU4uUGFydGljaXBhbnRzLGZpbGw9TmVjZXNzaXR5KSkgKyBnZW9tX2Jhcihwb3NpdGlvbj0iZG9kZ2UiLGNvbG91cj0id2hpdGUiLHN0YXQ9ImlkZW50aXR5IikgICsgbGFicyh5PSJOIHBhcnRpY2lwYW50cyIpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwzNSwxMCksbGltaXRzPWMoMCwzNSkpICsgdGhlbWVfYncoKSArIGdndGl0bGUoIk5lY2Vzc2l0eSBieSBDb250ZXh0IikrICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTi5QYXJ0aWNpcGFudHMpLCBoanVzdD0wLjUsIHZqdXN0PS0wLjI1LCBzaXplID0gMi41LHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSkpIApgYGAKCiMgQ29ycmVsYXRpb24gcGxvdCBvZiBpdGVtcyBieSBjb250ZXh0CgojIyBJdGFsaWFuIGluIEF1c3RyYWxpYQoKYGBge3IgY29yX2l0YWxpYW5faW5fYXVzdHJhbGlhLGZpZy53aWR0aD0xNSxmaWcuaGVpZ2h0PTE1fQpjb3YgPC0gY29yKGZpbHRlcmVkX2NvbnZbZmlsdGVyZWRfY29udiRDb250ZXh0ID09ICJJdGFsaWFuIGluIEF1c3RyYWxpYSIsbGlrZXJ0X3ZhcmlhYmxlczFbIShsaWtlcnRfdmFyaWFibGVzMSAlaW4lICJuZWNlc3NpdHkxIildXSxtZXRob2QgPSAicGVhcnNvbiIsdXNlPSJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQpkYXRhX2Nvcl9pdGFfaW5fYXUgPC0gZGF0YS5mcmFtZShjb3JfaXRhX2luX2F1PWNvdltsb3dlci50cmkoY292LCBkaWFnID0gVFJVRSldLAogICAgICAgICAgICAgICAgdmFyMSA9IHJvd25hbWVzKGNvdilbdW5saXN0KHQobWFwcGx5KCI6IiwgMTpucm93KGNvdiksIG5yb3coY292KSkpWzEsXSldLAogICAgICAgICAgICAgICAgdmFyMiA9IHJlcChjb2xuYW1lcyhjb3YpLHRpbWVzPXJldihzZXEobnJvdyhjb3YpOjEpKSkpCgpyb3dfaW5mb3MgPC0gZGF0YS5mcmFtZShWYXJpYWJsZXM9c2FwcGx5KHN0cnNwbGl0KGNvbG5hbWVzKGNvdiksc3BsaXQ9IlxcLiIpLGZ1bmN0aW9uKHgpIHhbMl0pKQpyb3dfaW5mb3MkVmFyaWFibGVzIDwtIGFzLmNoYXJhY3Rlcihyb3dfaW5mb3MkVmFyaWFibGVzKQpyb3duYW1lcyhyb3dfaW5mb3MpIDwtIHJvd25hbWVzKGNvdikKcm93X2luZm9zJFZhcmlhYmxlc1t3aGljaChpcy5uYShyb3dfaW5mb3MkVmFyaWFibGVzKSldIDwtIGMoImVkdWNhdGVkIikKcm93X2luZm9zIDwtIHJvd19pbmZvc1tvcmRlcihyb3dfaW5mb3MkVmFyaWFibGVzKSwsZHJvcD1GQUxTRV0KCmFubl9jb2xfd2lkZSA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlPXVuaXF1ZShyb3dfaW5mb3MkVmFyaWFibGVzKSkKYW5uX2NvbG9yc193aWRlIDwtIGxpc3QoVmFyaWFibGVzPWMoY29tbTE9IiNiZDAwMjYiLGVkdWNhdGVkPSIjYjM1ODA2IiwgaWQxPSIjZjZlOGMzIixpbnN0cnUxPSIjMzU5NzhmIixpbnRlZ3IxPSIjMzg2Y2IwIixpbnRyMT0iI2ZmZmY5OSIsb3VnaHQxPSJncmV5Iixwb3N0MT0iYmxhY2siLHByb2YxPSJwaW5rIikpCgojcGhlYXRtYXAoY292LCBtYWluID0gIkl0YWxpYW4gaW4gQXVzdHJhbGlhIixhbm5vdGF0aW9uX25hbWVzX3JvdyA9IEZBTFNFLGNsdXN0ZXJfY29scz1UUlVFLGNsdXN0ZXJfcm93cz1UUlVFLGFubm90YXRpb25fY29sID0gcm93X2luZm9zWywxLGRyb3A9RkFMU0VdLCBhbm5vdGF0aW9uX3JvdyA9IHJvd19pbmZvc1ssMSxkcm9wPUZBTFNFXSwgIGFubm90YXRpb25fY29sb3JzID0gYW5uX2NvbG9yc193aWRlLGJyZWFrcz1zZXEoLTEsMSwwLjIpLGNvbD1jKCIjNjcwMDFmIiwiI2IyMTgyYiIsIiNkNjYwNGQiLCIjZjRhNTgyIiwiI2ZkZGJjNyIsIiNmN2Y3ZjciLCIjZDFlNWYwIiwiIzkyYzVkZSIsIiM0MzkzYzMiLCIjMjE2NmFjIiwiIzA1MzA2MSIpLHNob3dfY29sbmFtZXMgPSBGQUxTRSx3aWR0aCA9IDcsaGVpZ2h0ID0gNykKIyMjIyMjIyMjIyMjIyMjIyMjIwoKZGlhZyhjb3YpIDwtIE5BCnBoZWF0bWFwKGNvdiwgbWFpbiA9ICJJdGFsaWFuIGluIEF1c3RyYWxpYSIsYW5ub3RhdGlvbl9uYW1lc19yb3cgPSBGQUxTRSxjbHVzdGVyX2NvbHM9VFJVRSxjbHVzdGVyX3Jvd3M9VFJVRSxhbm5vdGF0aW9uX2NvbCA9IHJvd19pbmZvc1ssMSxkcm9wPUZBTFNFXSwgYW5ub3RhdGlvbl9yb3cgPSByb3dfaW5mb3NbLDEsZHJvcD1GQUxTRV0KLCAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5fY29sb3JzX3dpZGUsc2hvd19jb2xuYW1lcyA9IEZBTFNFLGJyZWFrcyA9IHNlcSgtMC42LDAuNyxsZW5ndGgub3V0ID0gNTApLHdpZHRoID0gNyxoZWlnaHQgPSA3LGNvbG9yPWNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbChuID0gNywgbmFtZSA9ICJSZEJ1IikpKDUwKSkKCmNvdl9JdGFBdXMgPC0gY292CmBgYAoKIyMgR2VybWFuIGluIEF1c3RyYWxpYQoKYGBge3IgY29yX2dlcm1hbl9pbl9hdXN0cmFsaWEsZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MTV9CmNvdiA8LSBjb3IoZmlsdGVyZWRfY29udltmaWx0ZXJlZF9jb252JENvbnRleHQgPT0gIkdlcm1hbiBpbiBBdXN0cmFsaWEiLGxpa2VydF92YXJpYWJsZXMxWyEobGlrZXJ0X3ZhcmlhYmxlczEgJWluJSAibmVjZXNzaXR5MSIpXV0sbWV0aG9kID0gInBlYXJzb24iLHVzZT0icGFpcndpc2UuY29tcGxldGUub2JzIikKZGF0YV9jb3JfZ2VybV9pbl9hdSA8LSBkYXRhLmZyYW1lKGNvcl9nZXJtX2luX2F1PWNvdltsb3dlci50cmkoY292LCBkaWFnID0gVFJVRSldLAogICAgICAgICAgICAgICAgdmFyMSA9IHJvd25hbWVzKGNvdilbdW5saXN0KHQobWFwcGx5KCI6IiwgMTpucm93KGNvdiksIG5yb3coY292KSkpWzEsXSldLAogICAgICAgICAgICAgICAgdmFyMiA9IHJlcChjb2xuYW1lcyhjb3YpLHRpbWVzPXJldihzZXEobnJvdyhjb3YpOjEpKSkpCgoKCnJvd19pbmZvcyA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlcz1zYXBwbHkoc3Ryc3BsaXQoY29sbmFtZXMoY292KSxzcGxpdD0iXFwuIiksZnVuY3Rpb24oeCkgeFsyXSkpCnJvd19pbmZvcyRWYXJpYWJsZXMgPC0gYXMuY2hhcmFjdGVyKHJvd19pbmZvcyRWYXJpYWJsZXMpCnJvd25hbWVzKHJvd19pbmZvcykgPC0gcm93bmFtZXMoY292KQpyb3dfaW5mb3MkVmFyaWFibGVzW3doaWNoKGlzLm5hKHJvd19pbmZvcyRWYXJpYWJsZXMpKV0gPC0gYygiZWR1Y2F0ZWQiKQpyb3dfaW5mb3MgPC0gcm93X2luZm9zW29yZGVyKHJvd19pbmZvcyRWYXJpYWJsZXMpLCxkcm9wPUZBTFNFXQoKYW5uX2NvbF93aWRlIDwtIGRhdGEuZnJhbWUoVmFyaWFibGU9dW5pcXVlKHJvd19pbmZvcyRWYXJpYWJsZXMpKQphbm5fY29sb3JzX3dpZGUgPC0gbGlzdChWYXJpYWJsZXM9Yyhjb21tMT0iI2JkMDAyNiIsZWR1Y2F0ZWQ9IiNiMzU4MDYiLCBpZDE9IiNmNmU4YzMiLGluc3RydTE9IiMzNTk3OGYiLGludGVncjE9IiMzODZjYjAiLGludHIxPSIjZmZmZjk5IixvdWdodDE9ImdyZXkiLHBvc3QxPSJibGFjayIscHJvZjE9InBpbmsiKSkKCmRpYWcoY292KSA8LSBOQQpwaGVhdG1hcChjb3YsIG1haW4gPSAiR2VybWFuIGluIEF1c3RyYWxpYSIsYW5ub3RhdGlvbl9uYW1lc19yb3cgPSBGQUxTRSxjbHVzdGVyX2NvbHM9VFJVRSxjbHVzdGVyX3Jvd3M9VFJVRSxhbm5vdGF0aW9uX2NvbCA9IHJvd19pbmZvc1ssMSxkcm9wPUZBTFNFXSwgYW5ub3RhdGlvbl9yb3cgPSByb3dfaW5mb3NbLDEsZHJvcD1GQUxTRV0KLCAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5fY29sb3JzX3dpZGUsc2hvd19jb2xuYW1lcyA9IEZBTFNFLGJyZWFrcyA9IHNlcSgtMC42LDAuNyxsZW5ndGgub3V0ID0gNTApLHdpZHRoID0gNyxoZWlnaHQgPSA3LGNvbG9yPWNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbChuID0gNywgbmFtZSA9ICJSZEJ1IikpKDUwKSkKCiMgCmNvdl9HZXJtQXVzIDwtIGNvdgpgYGAKCiMjIEVuZ2xpc2ggaW4gR2VybWFueQoKYGBge3IgY29yX2VuZ2xpc2hfaW5fZ2VybWFueSxmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0xNX0KY292IDwtIGNvcihmaWx0ZXJlZF9jb252W2ZpbHRlcmVkX2NvbnYkQ29udGV4dCA9PSAiRW5nbGlzaCBpbiBHZXJtYW55IixsaWtlcnRfdmFyaWFibGVzMVshKGxpa2VydF92YXJpYWJsZXMxICVpbiUgYygicmVjb25uZWN0LmNvbW0xIiwgICAgInNwZWFrZXJzbWVsYi5jb21tMSIsImNvbWVjbG9zZXIuY29tbTEiLCJlZHVjYXRlZDEiKSldXSxtZXRob2QgPSAicGVhcnNvbiIsdXNlPSJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQpkYXRhX2Nvcl9lbmdfaW5fZ2VybSA8LSBkYXRhLmZyYW1lKGNvcl9lbmdfaW5fZ2VybT1jb3ZbbG93ZXIudHJpKGNvdiwgZGlhZyA9IFRSVUUpXSwKICAgICAgICAgICAgICAgIHZhcjEgPSByb3duYW1lcyhjb3YpW3VubGlzdCh0KG1hcHBseSgiOiIsIDE6bnJvdyhjb3YpLCBucm93KGNvdikpKVsxLF0pXSwKICAgICAgICAgICAgICAgIHZhcjIgPSByZXAoY29sbmFtZXMoY292KSx0aW1lcz1yZXYoc2VxKG5yb3coY292KToxKSkpKQoKCnJvd19pbmZvcyA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlcz1zYXBwbHkoc3Ryc3BsaXQoY29sbmFtZXMoY292KSxzcGxpdD0iXFwuIiksZnVuY3Rpb24oeCkgeFsyXSkpCnJvd19pbmZvcyRWYXJpYWJsZXMgPC0gYXMuY2hhcmFjdGVyKHJvd19pbmZvcyRWYXJpYWJsZXMpCnJvd25hbWVzKHJvd19pbmZvcykgPC0gcm93bmFtZXMoY292KQpyb3dfaW5mb3MkVmFyaWFibGVzW3doaWNoKGlzLm5hKHJvd19pbmZvcyRWYXJpYWJsZXMpKV0gPC0gYygibmVjZXNzaXR5IikKcm93X2luZm9zIDwtIHJvd19pbmZvc1tvcmRlcihyb3dfaW5mb3MkVmFyaWFibGVzKSwsZHJvcD1GQUxTRV0KCmFubl9jb2xfd2lkZSA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlPXVuaXF1ZShyb3dfaW5mb3MkVmFyaWFibGVzKSkKYW5uX2NvbG9yc193aWRlIDwtIGxpc3QoVmFyaWFibGVzPWMoaWQxPSIjZjZlOGMzIixuZWNlc3NpdHk9IiNiMzU4MDYiLGluc3RydTE9IiMzNTk3OGYiLGludGVncjE9IiMzODZjYjAiLGludHIxPSIjZmZmZjk5IixvdWdodDE9ImdyZXkiLHBvc3QxPSJibGFjayIscHJvZjE9InBpbmsiKSkKCmRpYWcoY292KSA8LSBOQQpwaGVhdG1hcChjb3YsIG1haW4gPSAiRW5nbGlzaCBpbiBHZXJtYW55Iixhbm5vdGF0aW9uX25hbWVzX3JvdyA9IEZBTFNFLGNsdXN0ZXJfY29scz1UUlVFLGNsdXN0ZXJfcm93cz1UUlVFLGFubm90YXRpb25fY29sID0gcm93X2luZm9zWywxLGRyb3A9RkFMU0VdLCBhbm5vdGF0aW9uX3JvdyA9IHJvd19pbmZvc1ssMSxkcm9wPUZBTFNFXQosICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubl9jb2xvcnNfd2lkZSxzaG93X2NvbG5hbWVzID0gRkFMU0UsYnJlYWtzID0gc2VxKC0wLjYsMC43LGxlbmd0aC5vdXQgPSA1MCksd2lkdGggPSA3LGhlaWdodCA9IDcsY29sb3I9Y29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKG4gPSA3LCBuYW1lID0gIlJkQnUiKSkoNTApKQoKY292X0VuZ0dlcm0gPC0gY292CmBgYAoKIyMgRW5nbGlzaCBpbiBJdGFseQoKYGBge3IgY29yX2VuZ2xpc2hfaW5faXRhbHksZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MTV9CmNvdiA8LSBjb3IoZmlsdGVyZWRfY29udltmaWx0ZXJlZF9jb252JENvbnRleHQgPT0gIkVuZ2xpc2ggaW4gSXRhbHkiLGxpa2VydF92YXJpYWJsZXMxWyEobGlrZXJ0X3ZhcmlhYmxlczEgJWluJSBjKCJyZWNvbm5lY3QuY29tbTEiLCJzcGVha2Vyc21lbGIuY29tbTEiLCJjb21lY2xvc2VyLmNvbW0xIiwiZWR1Y2F0ZWQxIikpXV0sbWV0aG9kID0gInBlYXJzb24iLHVzZT0icGFpcndpc2UuY29tcGxldGUub2JzIikKZGF0YV9jb3JfZW5nX2luX2l0YSA8LSBkYXRhLmZyYW1lKGNvcl9lbmdfaW5faXRhPWNvdltsb3dlci50cmkoY292LCBkaWFnID0gVFJVRSldLAogICAgICAgICAgICAgICAgdmFyMSA9IHJvd25hbWVzKGNvdilbdW5saXN0KHQobWFwcGx5KCI6IiwgMTpucm93KGNvdiksIG5yb3coY292KSkpWzEsXSldLAogICAgICAgICAgICAgICAgdmFyMiA9IHJlcChjb2xuYW1lcyhjb3YpLHRpbWVzPXJldihzZXEobnJvdyhjb3YpOjEpKSkpCgoKcm93X2luZm9zIDwtIGRhdGEuZnJhbWUoVmFyaWFibGVzPXNhcHBseShzdHJzcGxpdChjb2xuYW1lcyhjb3YpLHNwbGl0PSJcXC4iKSxmdW5jdGlvbih4KSB4WzJdKSkKcm93X2luZm9zJFZhcmlhYmxlcyA8LSBhcy5jaGFyYWN0ZXIocm93X2luZm9zJFZhcmlhYmxlcykKcm93bmFtZXMocm93X2luZm9zKSA8LSByb3duYW1lcyhjb3YpCnJvd19pbmZvcyRWYXJpYWJsZXNbd2hpY2goaXMubmEocm93X2luZm9zJFZhcmlhYmxlcykpXSA8LSAibmVjZXNzaXR5Igpyb3dfaW5mb3MgPC0gcm93X2luZm9zW29yZGVyKHJvd19pbmZvcyRWYXJpYWJsZXMpLCxkcm9wPUZBTFNFXQoKYW5uX2NvbF93aWRlIDwtIGRhdGEuZnJhbWUoVmFyaWFibGU9dW5pcXVlKHJvd19pbmZvcyRWYXJpYWJsZXMpKQphbm5fY29sb3JzX3dpZGUgPC0gbGlzdChWYXJpYWJsZXM9Yyhjb21tMT0iI2JkMDAyNiIsbmVjZXNzaXR5PSIjYjM1ODA2IiwgaWQxPSIjZjZlOGMzIixpbnN0cnUxPSIjMzU5NzhmIixpbnRlZ3IxPSIjMzg2Y2IwIixpbnRyMT0iI2ZmZmY5OSIsb3VnaHQxPSJncmV5Iixwb3N0MT0iYmxhY2siLHByb2YxPSJwaW5rIikpCgpkaWFnKGNvdikgPC0gTkEKcGhlYXRtYXAoY292LCBtYWluID0gIkVuZ2xpc2ggaW4gSXRhbHkiLGFubm90YXRpb25fbmFtZXNfcm93ID0gRkFMU0UsY2x1c3Rlcl9jb2xzPVRSVUUsY2x1c3Rlcl9yb3dzPVRSVUUsYW5ub3RhdGlvbl9jb2wgPSByb3dfaW5mb3NbLDEsZHJvcD1GQUxTRV0sIGFubm90YXRpb25fcm93ID0gcm93X2luZm9zWywxLGRyb3A9RkFMU0VdCiwgIGFubm90YXRpb25fY29sb3JzID0gYW5uX2NvbG9yc193aWRlLHNob3dfY29sbmFtZXMgPSBGQUxTRSxicmVha3MgPSBzZXEoLTAuNiwwLjcsbGVuZ3RoLm91dCA9IDUwKSx3aWR0aCA9IDcsaGVpZ2h0ID0gNyxjb2xvcj1jb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPSAiUmRCdSIpKSg1MCkpCgojIApjb3ZfRW5nSXRhIDwtIGNvdgpgYGAKCiMjIENvcnJlbGF0aW9uIGJldHdlZW4gY29ycmVsYXRpb24gaW4gdGhlIGRpZmZlcmVudCBjb250ZXh0cwoKV2Ugd2lsbCBwZXJmb3JtIGFuIGV4cGxvcmF0b3J5IEZBIGNvbWJpbmluZyBhbGwgdGhlIGNvbnRleHRzIHRvZ2V0aGVyLiBUaGlzIG1lYW5zIHRoYXQgd2UgYXJlIGFzc3VtaW5nIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gaXRlbXMgYWNyb3NzIGNvbnRleHQgaGFzIHRoZSBzYW1lIGRpcmVjdGlvbiAoZG9lcyBub3QgaGFwcGVuIHRoYXQgY29yKGl0ZW0xLGl0ZW0yKV9jb250ZXh0MSA+IDAgYW5kIGNvcihpdGVtMSxpdGVtMilfY29udGV4dDIgPCAwKS4gCgpgYGB7ciBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0xMH0KY29tbW9uIDwtIHJvd25hbWVzKGNvdl9FbmdJdGEpW3Jvd25hbWVzKGNvdl9FbmdJdGEpICVpbiUgcm93bmFtZXMoY292X0l0YUF1cyldCnN1bShyb3duYW1lcyhjb3ZfRW5nSXRhKSAhPSByb3duYW1lcyhjb3ZfRW5nR2VybSkpCnN1bShyb3duYW1lcyhjb3ZfRW5nSXRhKSAhPSByb3duYW1lcyhjb3ZfR2VybUF1cykpCnN1bShyb3duYW1lcyhjb3ZfRW5nSXRhKSAhPSByb3duYW1lcyhjb3ZfSXRhQXVzKSkKc3VtKHJvd25hbWVzKGNvdl9HZXJtQXVzKSAhPSByb3duYW1lcyhjb3ZfSXRhQXVzKSkKCmNvbW1vbl9FbmdJdGEgPC0gY292X0VuZ0l0YVtyb3duYW1lcyhjb3ZfRW5nSXRhKSAlaW4lIGNvbW1vbixjb2xuYW1lcyhjb3ZfRW5nSXRhKSAlaW4lIGNvbW1vbl0KY29tbW9uX0VuZ0dlcm0gPC0gY292X0VuZ0dlcm1bcm93bmFtZXMoY292X0VuZ0dlcm0pICVpbiUgY29tbW9uLGNvbG5hbWVzKGNvdl9FbmdHZXJtKSAlaW4lIGNvbW1vbl0KY29tbW9uX0dlcm1BdXMgPC0gY292X0dlcm1BdXNbcm93bmFtZXMoY292X0dlcm1BdXMpICVpbiUgY29tbW9uLGNvbG5hbWVzKGNvdl9HZXJtQXVzKSAlaW4lIGNvbW1vbl0KY29tbW9uX0l0YUF1cyA8LSBjb3ZfSXRhQXVzW3Jvd25hbWVzKGNvdl9JdGFBdXMpICVpbiUgY29tbW9uLGNvbG5hbWVzKGNvdl9JdGFBdXMpICVpbiUgY29tbW9uXQoKc3VtKHJvd25hbWVzKGNvbW1vbl9FbmdJdGEpICE9IGNvbG5hbWVzKGNvbW1vbl9FbmdJdGEpKQpzdW0ocm93bmFtZXMoY29tbW9uX0VuZ0dlcm0pICE9IGNvbG5hbWVzKGNvbW1vbl9FbmdHZXJtKSkKc3VtKHJvd25hbWVzKGNvbW1vbl9HZXJtQXVzKSAhPSBjb2xuYW1lcyhjb21tb25fR2VybUF1cykpCnN1bShyb3duYW1lcyhjb21tb25fSXRhQXVzKSAhPSBjb2xuYW1lcyhjb21tb25fSXRhQXVzKSkKCgpwYXIobWZyb3c9YygyLDMpKQpwbG90KGNvbW1vbl9FbmdJdGEsY29tbW9uX0VuZ0dlcm0pCmFibGluZShoPWMoMCwwLjMpLHY9YygwLDAuMyksbHR5PTIsY29sID0gImRhcmsgcmVkIikKYWJsaW5lKGE9MCxiPTEsbHR5PTIsY29sID0gImRhcmsgcmVkIikKcGxvdChjb21tb25fRW5nSXRhLGNvbW1vbl9HZXJtQXVzKQphYmxpbmUoaD1jKDAsMC4zKSx2PWMoMCwwLjMpLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCmFibGluZShhPTAsYj0xLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCnBsb3QoY29tbW9uX0VuZ0l0YSxjb21tb25fSXRhQXVzKQphYmxpbmUoaD1jKDAsMC4zKSx2PWMoMCwwLjMpLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCmFibGluZShhPTAsYj0xLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCgpwbG90KGNvbW1vbl9FbmdHZXJtLGNvbW1vbl9HZXJtQXVzKQphYmxpbmUoaD1jKDAsMC4zKSx2PWMoMCwwLjMpLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCmFibGluZShhPTAsYj0xLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCnBsb3QoY29tbW9uX0VuZ0dlcm0sY29tbW9uX0l0YUF1cykKYWJsaW5lKGg9YygwLDAuMyksdj1jKDAsMC4zKSxsdHk9Mixjb2wgPSAiZGFyayByZWQiKQphYmxpbmUoYT0wLGI9MSxsdHk9Mixjb2wgPSAiZGFyayByZWQiKQoKcGxvdChjb21tb25fR2VybUF1cyxjb21tb25fSXRhQXVzKQphYmxpbmUoaD1jKDAsMC4zKSx2PWMoMCwwLjMpLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCmFibGluZShhPTAsYj0xLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCgojIExhcmdlc3QgZGlmZmVyZW5jZXMKbG93X0VuZ0dlcm0gPC0gbG93ZXIudHJpKGNvbW1vbl9FbmdHZXJtKQpjb21tb25fRW5nR2VybVshbG93X0VuZ0dlcm1dIDwtIE5BCmNvbW1vbl9HZXJtQXVzWyEobG93ZXIudHJpKGNvbW1vbl9HZXJtQXVzKSldIDwtIE5BCmNvbW1vbl9JdGFBdXNbIShsb3dlci50cmkoY29tbW9uX0l0YUF1cykpXSA8LSBOQQpjb21tb25fRW5nSXRhWyEobG93ZXIudHJpKGNvbW1vbl9FbmdJdGEpKV0gPC0gTkEKCgptYXQgPC0gZGF0YS5mcmFtZShjb21tb25fRW5nR2VybT1jKGNvbW1vbl9FbmdHZXJtKSwKICAgICAgICAgICAgICAgICAgY29tbW9uX0VuZ0l0YT1jKGNvbW1vbl9FbmdJdGEpLAogICAgICAgICAgICAgICAgICBjb21tb25fR2VybUF1cyA9IGMoY29tbW9uX0dlcm1BdXMpLAogICAgICAgICAgICAgICAgICBjb21tb25fSXRhQXVzID0gYyhjb21tb25fSXRhQXVzKSwKICAgICAgICAgICAgICAgICAgY29tcGFyZSA9IHBhc3RlKHJvd25hbWVzKGNvbW1vbl9FbmdHZXJtKSxjb2xuYW1lcyhjb21tb25fRW5nR2VybSksc2VwPSIuIikpICU+JQogIGZpbHRlcighaXMubmEoY29tbW9uX0VuZ0dlcm0pKSAlPiUKICBzZXBhcmF0ZShjb21wYXJlLGludG89YygiaXRlbTEiLCJ2YXJpYWJsZTEiLCJpdGVtMiIsInZhcmlhYmxlMiIpLHJlbW92ZT1GQUxTRSxzZXA9IlsuXSIpICU+JQogIHVuaXRlKGdyb3VwLHZhcmlhYmxlMSx2YXJpYWJsZTIsc2VwPSIuIikKCmxpYnJhcnkoZ2dyZXBlbCkKZ2dwbG90KG1hdCxhZXMoeD1jb21tb25fRW5nR2VybSx5PWNvbW1vbl9HZXJtQXVzLGxhYmVsPWNvbXBhcmUsY29sb3VyPWdyb3VwKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSxzaXplPTAuOCkgKyBnZW9tX3RleHQoc2l6ZT0yKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PWMoMCwwLjMpLGxpbmV0eXBlPSJkb3R0ZWQiLGNvbG91cj0iZGFyayByZWQiKSArCmdlb21fdmxpbmUoeGludGVyY2VwdD1jKDAsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikKCgpnZ3Bsb3QobWF0LGFlcyh4PWNvbW1vbl9FbmdHZXJtLHk9Y29tbW9uX0l0YUF1cyxsYWJlbD1jb21wYXJlLGNvbG91cj1ncm91cCkpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUsc2l6ZT0wLjgpICsgZ2VvbV90ZXh0KHNpemU9MikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD1jKDAsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikgKwpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YygwLDAuMyksbGluZXR5cGU9ImRvdHRlZCIsY29sb3VyPSJkYXJrIHJlZCIpCgpnZ3Bsb3QobWF0LGFlcyh4PWNvbW1vbl9FbmdHZXJtLHk9Y29tbW9uX0VuZ0l0YSxsYWJlbD1jb21wYXJlLGNvbG91cj1ncm91cCkpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUsc2l6ZT0wLjgpICsgZ2VvbV90ZXh0KHNpemU9MikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD1jKDAsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikgKwpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YygwLDAuMyksbGluZXR5cGU9ImRvdHRlZCIsY29sb3VyPSJkYXJrIHJlZCIpCgpgYGAKCgojIyBEaWZmZXJlbnQgY29ycmVsYXRpb24gcGxvdCBhbmQgUGVhcnNvbidzIGNvcnJlbGF0aW9uCgpgYGB7ciBmaWcud2lkdGg9MTIsZmlnLmhlaWdodD04LCBpbmNsdWRlPUZBTFNFfQpjb21tb24gPC0gcm93bmFtZXMoY292X0VuZ0l0YSlbcm93bmFtZXMoY292X0VuZ0l0YSkgJWluJSByb3duYW1lcyhjb3ZfSXRhQXVzKV0Kc3VtKHJvd25hbWVzKGNvdl9FbmdJdGEpICE9IHJvd25hbWVzKGNvdl9FbmdHZXJtKSkKc3VtKHJvd25hbWVzKGNvdl9FbmdJdGEpICE9IHJvd25hbWVzKGNvdl9HZXJtQXVzKSkKc3VtKHJvd25hbWVzKGNvdl9FbmdJdGEpICE9IHJvd25hbWVzKGNvdl9JdGFBdXMpKQpzdW0ocm93bmFtZXMoY292X0dlcm1BdXMpICE9IHJvd25hbWVzKGNvdl9JdGFBdXMpKQoKY29tbW9uX0VuZ0l0YSA8LSBjb3ZfRW5nSXRhW3Jvd25hbWVzKGNvdl9FbmdJdGEpICVpbiUgY29tbW9uLGNvbG5hbWVzKGNvdl9FbmdJdGEpICVpbiUgY29tbW9uXQpjb21tb25fRW5nR2VybSA8LSBjb3ZfRW5nR2VybVtyb3duYW1lcyhjb3ZfRW5nR2VybSkgJWluJSBjb21tb24sY29sbmFtZXMoY292X0VuZ0dlcm0pICVpbiUgY29tbW9uXQpjb21tb25fR2VybUF1cyA8LSBjb3ZfR2VybUF1c1tyb3duYW1lcyhjb3ZfR2VybUF1cykgJWluJSBjb21tb24sY29sbmFtZXMoY292X0dlcm1BdXMpICVpbiUgY29tbW9uXQpjb21tb25fSXRhQXVzIDwtIGNvdl9JdGFBdXNbcm93bmFtZXMoY292X0l0YUF1cykgJWluJSBjb21tb24sY29sbmFtZXMoY292X0l0YUF1cykgJWluJSBjb21tb25dCgpzdW0ocm93bmFtZXMoY29tbW9uX0VuZ0l0YSkgIT0gY29sbmFtZXMoY29tbW9uX0VuZ0l0YSkpCnN1bShyb3duYW1lcyhjb21tb25fRW5nR2VybSkgIT0gY29sbmFtZXMoY29tbW9uX0VuZ0dlcm0pKQpzdW0ocm93bmFtZXMoY29tbW9uX0dlcm1BdXMpICE9IGNvbG5hbWVzKGNvbW1vbl9HZXJtQXVzKSkKc3VtKHJvd25hbWVzKGNvbW1vbl9JdGFBdXMpICE9IGNvbG5hbWVzKGNvbW1vbl9JdGFBdXMpKQoKY29udGV4dHNfZGYgPC0gZGF0YS5mcmFtZSh4ID0gYygiY29tbW9uX0VuZ0l0YSIsImNvbW1vbl9FbmdJdGEiLCJjb21tb25fRW5nSXRhIiwKImNvbW1vbl9FbmdHZXJtIiwiY29tbW9uX0VuZ0dlcm0iLAoiY29tbW9uX0dlcm1BdXMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYygiY29tbW9uX0VuZ0dlcm0iLCJjb21tb25fSXRhQXVzIiwiY29tbW9uX0dlcm1BdXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb21tb25fR2VybUF1cyIsImNvbW1vbl9JdGFBdXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbW1vbl9JdGFBdXMiKSkgJT4lCiAgdGlkeXI6OnVuaXRlKG5hbWUseCx5LHNlcD0iLSIscmVtb3ZlPUZBTFNFKQoKc2NvciA8LSB2ZWN0b3IoImxpc3QiLGxlbmd0aD1ucm93KGNvbnRleHRzX2RmKSkKbmFtZXMoc2NvcikgPC0gY29udGV4dHNfZGYkbmFtZQpuYW1lc19wbG90IDwtIHBhc3RlMCgicCIsMTpucm93KGNvbnRleHRzX2RmKSkKbmFtZXNfcGxvdDEgPC0gcGFzdGUwKCJwX3ZhcjFfIiwxOm5yb3coY29udGV4dHNfZGYpKQpuYW1lc19wbG90MiA8LSBwYXN0ZTAoInBfdmFyMl8iLDE6bnJvdyhjb250ZXh0c19kZikpCgpmb3IoaSBpbiAxOm5yb3coY29udGV4dHNfZGYpKSB7CiAgCiAgY29tcCA8LSBjb250ZXh0c19kZltpLF0KICBjb250MSA8LSBnZXQoYXMuY2hhcmFjdGVyKGNvbXAkeCkpCiAgY29udDIgPC0gZ2V0KGFzLmNoYXJhY3Rlcihjb21wJHkpKQogIAogIG5hbWVzX2NvbXAgPC0gZGF0YS5mcmFtZShpdGVtMSA9IHJlcChjb2xuYW1lcyhjb250MSksZWFjaD1uY29sKGNvbnQxKSksCiAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtMiA9IHJlcChjb2xuYW1lcyhjb250MSksCiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVzPW5jb2woY29udDEpKSkgJT4lCiAgdGlkeXI6OnVuaXRlKG5hbWVfY29tcCwgaXRlbTEsaXRlbTIsc2VwPSItIixyZW1vdmU9RkFMU0UpICU+JQogIHRpZHlyOjp1bml0ZShuYW1lX2NvbXAxLCBpdGVtMixpdGVtMSxzZXA9Ii0iLHJlbW92ZT1GQUxTRSkgJT4lCiAgZHBseXI6Om11dGF0ZShjb250MV92ZWMgPSBjKGNvbnQxKSwKICAgICAgICAgICAgICAgIGNvbnQyX3ZlYyA9IGMoY29udDIpKSAlPiUKICBkcGx5cjo6ZmlsdGVyKG5hbWVfY29tcCAhPSBuYW1lX2NvbXAxKSAlPiUKICAgIHRpZHlyOjpzZXBhcmF0ZShpdGVtMSAsIGludG89YygidHlwZTEiLCJ2YXJpYWJsZTEiKSxzZXA9IlsuXSIscmVtb3ZlPUZBTFNFKSAlPiUKICAgIHRpZHlyOjpzZXBhcmF0ZShpdGVtMiAsIGludG89YygidHlwZTIiLCJ2YXJpYWJsZTIiKSxzZXA9IlsuXSIscmVtb3ZlPUZBTFNFKQoKc2NvcltbaV1dID0gY29yKG5hbWVzX2NvbXAkY29udDFfdmVjLG5hbWVzX2NvbXAkY29udDJfdmVjKQphc3NpZ24obmFtZXNfcGxvdFtpXSxnZ3Bsb3QobmFtZXNfY29tcCxhZXMoeD1jb250MV92ZWMseT1jb250Ml92ZWMpKSArIGdlb21faGV4KCkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMC4zLDAuMyksbGluZXR5cGU9ImRvdHRlZCIsY29sb3VyPSJkYXJrIHJlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC0wLjMsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikrCiAgbGFicyh4PXBhc3RlMChnc3ViKCJjb21tb25fIiwiIixhcy5jaGFyYWN0ZXIoY29tcCR4KSkpLHk9Z3N1YigiY29tbW9uXyIsIiIsYXMuY2hhcmFjdGVyKGNvbXAkeSkpKSkKICAKYXNzaWduKG5hbWVzX3Bsb3QxW2ldLGdncGxvdChuYW1lc19jb21wLGFlcyh4PWNvbnQxX3ZlYyx5PWNvbnQyX3ZlYyxjb2xvdXI9dmFyaWFibGUxKSkgKyBnZW9tX3BvaW50KCkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMC4zLDAuMyksbGluZXR5cGU9ImRvdHRlZCIsY29sb3VyPSJkYXJrIHJlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC0wLjMsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikrCiAgbGFicyh4PXBhc3RlMChnc3ViKCJjb21tb25fIiwiIixhcy5jaGFyYWN0ZXIoY29tcCR4KSkpLHk9Z3N1YigiY29tbW9uXyIsIiIsYXMuY2hhcmFjdGVyKGNvbXAkeSkpKSkKCiAgYXNzaWduKG5hbWVzX3Bsb3QyW2ldLGdncGxvdChuYW1lc19jb21wLGFlcyh4PWNvbnQxX3ZlYyx5PWNvbnQyX3ZlYyxjb2xvdXI9dmFyaWFibGUyKSkgKyBnZW9tX3BvaW50KCkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMC4zLDAuMyksbGluZXR5cGU9ImRvdHRlZCIsY29sb3VyPSJkYXJrIHJlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC0wLjMsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikrCiAgbGFicyh4PXBhc3RlMChnc3ViKCJjb21tb25fIiwiIixhcy5jaGFyYWN0ZXIoY29tcCR4KSkpLHk9Z3N1YigiY29tbW9uXyIsIiIsYXMuY2hhcmFjdGVyKGNvbXAkeSkpKSkKCnByaW50KGkpCiAgCn0KCmNvcl9kYXRhIDwtIGRhdGEuZnJhbWUoY29tcGFyaXNvbiA9IG5hbWVzKHNjb3IpLHJfc3F1YXJlZCA9IGRvLmNhbGwoYyxzY29yKSkgJT4lIAogIGFycmFuZ2Uocl9zcXVhcmVkKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMixmaWcuaGVpZ2h0PTh9CmNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixwMyxwNCxwNSxwNixucm93PTMpCmBgYAoKYGBge3J9CmtuaXRyOjprYWJsZShjb3JfZGF0YSkKYGBgCgoKCiMjIEFsbCBjb250ZXh0IHRvZ2V0aGVyCgpgYGB7ciBjb3JfYWxsX2NvbnRleHRzfQpjb3YgPC0gY29yKGZpbHRlcmVkX2NvbnZbLGxpa2VydF92YXJpYWJsZXMxXSxtZXRob2QgPSAicGVhcnNvbiIsdXNlPSJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQoKcm93X2luZm9zIDwtIGRhdGEuZnJhbWUoVmFyaWFibGVzPXNhcHBseShzdHJzcGxpdChjb2xuYW1lcyhjb3YpLHNwbGl0PSJcXC4iKSxmdW5jdGlvbih4KSB4WzJdKSkKcm93X2luZm9zJFZhcmlhYmxlcyA8LSBhcy5jaGFyYWN0ZXIocm93X2luZm9zJFZhcmlhYmxlcykKcm93bmFtZXMocm93X2luZm9zKSA8LSByb3duYW1lcyhjb3YpCnJvd19pbmZvcyRWYXJpYWJsZXNbd2hpY2goaXMubmEocm93X2luZm9zJFZhcmlhYmxlcykpXSA8LSBjKCJuZWNlc3NpdHkiLCJlZHVjYXRlZCIpCnJvd19pbmZvcyA8LSByb3dfaW5mb3Nbb3JkZXIocm93X2luZm9zJFZhcmlhYmxlcyksLGRyb3A9RkFMU0VdCgphbm5fY29sX3dpZGUgPC0gZGF0YS5mcmFtZShWYXJpYWJsZT11bmlxdWUocm93X2luZm9zJFZhcmlhYmxlcykpCmFubl9jb2xvcnNfd2lkZSA8LSBsaXN0KFZhcmlhYmxlcz1jKGNvbW0xPSIjYmQwMDI2IixlZHVjYXRlZD0ib3JhbmdlIiwgaWQxPSIjZjZlOGMzIixpbnN0cnUxPSIjMzU5NzhmIixuZWNlc3NpdHk9IiNiMzU4MDYiLGludGVncjE9IiMzODZjYjAiLGludHIxPSIjZmZmZjk5IixvdWdodDE9ImdyZXkiLHBvc3QxPSJibGFjayIscHJvZjE9InBpbmsiKSkKCmRpYWcoY292KSA8LSBOQQpwaGVhdG1hcChjb3YsIG1haW4gPSAiQWxsIENvbnRleHRzIixhbm5vdGF0aW9uX25hbWVzX3JvdyA9IEZBTFNFLGNsdXN0ZXJfY29scz1UUlVFLGNsdXN0ZXJfcm93cz1UUlVFLGFubm90YXRpb25fY29sID0gcm93X2luZm9zWywxLGRyb3A9RkFMU0VdLCBhbm5vdGF0aW9uX3JvdyA9IHJvd19pbmZvc1ssMSxkcm9wPUZBTFNFXQosICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubl9jb2xvcnNfd2lkZSxzaG93X2NvbG5hbWVzID0gRkFMU0UsYnJlYWtzID0gc2VxKC0wLjYsMC43LGxlbmd0aC5vdXQgPSA1MCksd2lkdGggPSA3LGhlaWdodCA9IDcsY29sb3I9Y29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKG4gPSA3LCBuYW1lID0gIlJkQnUiKSkoNTApKQoKYGBgCgojIyBDb21wYXJlIGNvcnJlbGF0aW9ucwoKYGBge3J9CmxpYnJhcnkoR0dhbGx5KQpjb21iaW5lX2NvciA8LSBtZXJnZShkYXRhX2Nvcl9lbmdfaW5faXRhLGRhdGFfY29yX2VuZ19pbl9nZXJtLGFsbCA9IFRSVUUpCmNvbWJpbmVfY29yMSA8LSBtZXJnZShjb21iaW5lX2NvcixkYXRhX2Nvcl9nZXJtX2luX2F1LGFsbCA9IFRSVUUpCmNvbWJpbmVfY29yMiA8LSBtZXJnZShjb21iaW5lX2NvcjEsZGF0YV9jb3JfaXRhX2luX2F1LGFsbCA9IFRSVUUpCmNvbWJpbmVfY29yMiA8LSBjb21iaW5lX2NvcjIgJT4lIHNlcGFyYXRlKHZhcjEsaW50bz1jKCJpdGVtMSIsInZhcmlhYmxlMSIpLHNlcD0iWy5dIixyZW1vdmU9RkFMU0UpICU+JQogIHNlcGFyYXRlKHZhcjIsaW50bz1jKCJpdGVtMiIsInZhcmlhYmxlMiIpLHNlcD0iWy5dIixyZW1vdmU9RkFMU0UpICU+JQogIHVuaXRlKGdyb3VwLHZhcmlhYmxlMSx2YXJpYWJsZTIsc2VwPSIuIikKCnBhaXJzKGNvbWJpbmVfY29yMlssYygiY29yX2VuZ19pbl9pdGEiLCJjb3JfZW5nX2luX2dlcm0iLCJjb3JfZ2VybV9pbl9hdSIsImNvcl9pdGFfaW5fYXUiKV0pCmdncGFpcnMoY29tYmluZV9jb3IyWyxjKCJjb3JfZW5nX2luX2l0YSIsImNvcl9lbmdfaW5fZ2VybSIsImNvcl9nZXJtX2luX2F1IiwiY29yX2l0YV9pbl9hdSIpXSkKCmBgYAoKCiMjIENvcnJlbGF0aW9uIGJldHdlZW4gY29ycmVsYXRpb24gaW4gdGhlIGRpZmZlcmVudCBjb250ZXh0cwoKV2Ugd2lsbCBwZXJmb3JtIGFuIGV4cGxvcmF0b3J5IEZBIGNvbWJpbmluZyBhbGwgdGhlIGNvbnRleHRzIHRvZ2V0aGVyLiBUaGlzIG1lYW5zIHRoYXQgd2UgYXJlIGFzc3VtaW5nIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gaXRlbXMgYWNyb3NzIGNvbnRleHQgaGFzIHRoZSBzYW1lIGRpcmVjdGlvbiAoZG9lcyBub3QgaGFwcGVuIHRoYXQgY29yKGl0ZW0xLGl0ZW0yKV9jb250ZXh0MSA+IDAgYW5kIGNvcihpdGVtMSxpdGVtMilfY29udGV4dDIgPCAwKS4gCgpgYGB7ciBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0xMH0KY29tbW9uIDwtIHJvd25hbWVzKGNvdl9FbmdJdGEpW3Jvd25hbWVzKGNvdl9FbmdJdGEpICVpbiUgcm93bmFtZXMoY292X0l0YUF1cyldCnN1bShyb3duYW1lcyhjb3ZfRW5nSXRhKSAhPSByb3duYW1lcyhjb3ZfRW5nR2VybSkpCnN1bShyb3duYW1lcyhjb3ZfRW5nSXRhKSAhPSByb3duYW1lcyhjb3ZfR2VybUF1cykpCnN1bShyb3duYW1lcyhjb3ZfRW5nSXRhKSAhPSByb3duYW1lcyhjb3ZfSXRhQXVzKSkKc3VtKHJvd25hbWVzKGNvdl9HZXJtQXVzKSAhPSByb3duYW1lcyhjb3ZfSXRhQXVzKSkKCmNvbW1vbl9FbmdJdGEgPC0gY292X0VuZ0l0YVtyb3duYW1lcyhjb3ZfRW5nSXRhKSAlaW4lIGNvbW1vbixjb2xuYW1lcyhjb3ZfRW5nSXRhKSAlaW4lIGNvbW1vbl0KY29tbW9uX0VuZ0dlcm0gPC0gY292X0VuZ0dlcm1bcm93bmFtZXMoY292X0VuZ0dlcm0pICVpbiUgY29tbW9uLGNvbG5hbWVzKGNvdl9FbmdHZXJtKSAlaW4lIGNvbW1vbl0KY29tbW9uX0dlcm1BdXMgPC0gY292X0dlcm1BdXNbcm93bmFtZXMoY292X0dlcm1BdXMpICVpbiUgY29tbW9uLGNvbG5hbWVzKGNvdl9HZXJtQXVzKSAlaW4lIGNvbW1vbl0KY29tbW9uX0l0YUF1cyA8LSBjb3ZfSXRhQXVzW3Jvd25hbWVzKGNvdl9JdGFBdXMpICVpbiUgY29tbW9uLGNvbG5hbWVzKGNvdl9JdGFBdXMpICVpbiUgY29tbW9uXQoKc3VtKHJvd25hbWVzKGNvbW1vbl9FbmdJdGEpICE9IGNvbG5hbWVzKGNvbW1vbl9FbmdJdGEpKQpzdW0ocm93bmFtZXMoY29tbW9uX0VuZ0dlcm0pICE9IGNvbG5hbWVzKGNvbW1vbl9FbmdHZXJtKSkKc3VtKHJvd25hbWVzKGNvbW1vbl9HZXJtQXVzKSAhPSBjb2xuYW1lcyhjb21tb25fR2VybUF1cykpCnN1bShyb3duYW1lcyhjb21tb25fSXRhQXVzKSAhPSBjb2xuYW1lcyhjb21tb25fSXRhQXVzKSkKCgpwYXIobWZyb3c9YygyLDMpKQpwbG90KGNvbW1vbl9FbmdJdGEsY29tbW9uX0VuZ0dlcm0pCmFibGluZShoPWMoMCwwLjMpLHY9YygwLDAuMyksbHR5PTIsY29sID0gImRhcmsgcmVkIikKYWJsaW5lKGE9MCxiPTEsbHR5PTIsY29sID0gImRhcmsgcmVkIikKcGxvdChjb21tb25fRW5nSXRhLGNvbW1vbl9HZXJtQXVzKQphYmxpbmUoaD1jKDAsMC4zKSx2PWMoMCwwLjMpLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCmFibGluZShhPTAsYj0xLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCnBsb3QoY29tbW9uX0VuZ0l0YSxjb21tb25fSXRhQXVzKQphYmxpbmUoaD1jKDAsMC4zKSx2PWMoMCwwLjMpLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCmFibGluZShhPTAsYj0xLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCgpwbG90KGNvbW1vbl9FbmdHZXJtLGNvbW1vbl9HZXJtQXVzKQphYmxpbmUoaD1jKDAsMC4zKSx2PWMoMCwwLjMpLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCmFibGluZShhPTAsYj0xLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCnBsb3QoY29tbW9uX0VuZ0dlcm0sY29tbW9uX0l0YUF1cykKYWJsaW5lKGg9YygwLDAuMyksdj1jKDAsMC4zKSxsdHk9Mixjb2wgPSAiZGFyayByZWQiKQphYmxpbmUoYT0wLGI9MSxsdHk9Mixjb2wgPSAiZGFyayByZWQiKQoKcGxvdChjb21tb25fR2VybUF1cyxjb21tb25fSXRhQXVzKQphYmxpbmUoaD1jKDAsMC4zKSx2PWMoMCwwLjMpLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCmFibGluZShhPTAsYj0xLGx0eT0yLGNvbCA9ICJkYXJrIHJlZCIpCgojIExhcmdlc3QgZGlmZmVyZW5jZXMKbG93X0VuZ0dlcm0gPC0gbG93ZXIudHJpKGNvbW1vbl9FbmdHZXJtKQpjb21tb25fRW5nR2VybVshbG93X0VuZ0dlcm1dIDwtIE5BCmNvbW1vbl9HZXJtQXVzWyEobG93ZXIudHJpKGNvbW1vbl9HZXJtQXVzKSldIDwtIE5BCmNvbW1vbl9JdGFBdXNbIShsb3dlci50cmkoY29tbW9uX0l0YUF1cykpXSA8LSBOQQpjb21tb25fRW5nSXRhWyEobG93ZXIudHJpKGNvbW1vbl9FbmdJdGEpKV0gPC0gTkEKCgptYXQgPC0gZGF0YS5mcmFtZShjb21tb25fRW5nR2VybT1jKGNvbW1vbl9FbmdHZXJtKSwKICAgICAgICAgICAgICAgICAgY29tbW9uX0VuZ0l0YT1jKGNvbW1vbl9FbmdJdGEpLAogICAgICAgICAgICAgICAgICBjb21tb25fR2VybUF1cyA9IGMoY29tbW9uX0dlcm1BdXMpLAogICAgICAgICAgICAgICAgICBjb21tb25fSXRhQXVzID0gYyhjb21tb25fSXRhQXVzKSwKICAgICAgICAgICAgICAgICAgY29tcGFyZSA9IHBhc3RlKHJvd25hbWVzKGNvbW1vbl9FbmdHZXJtKSxjb2xuYW1lcyhjb21tb25fRW5nR2VybSksc2VwPSIuIikpICU+JQogIGZpbHRlcighaXMubmEoY29tbW9uX0VuZ0dlcm0pKSAlPiUKICBzZXBhcmF0ZShjb21wYXJlLGludG89YygiaXRlbTEiLCJ2YXJpYWJsZTEiLCJpdGVtMiIsInZhcmlhYmxlMiIpLHJlbW92ZT1GQUxTRSxzZXA9IlsuXSIpICU+JQogIHVuaXRlKGdyb3VwLHZhcmlhYmxlMSx2YXJpYWJsZTIsc2VwPSIuIikKCmxpYnJhcnkoZ2dyZXBlbCkKZ2dwbG90KG1hdCxhZXMoeD1jb21tb25fRW5nR2VybSx5PWNvbW1vbl9HZXJtQXVzLGxhYmVsPWNvbXBhcmUsY29sb3VyPWdyb3VwKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSxzaXplPTAuOCkgKyBnZW9tX3RleHQoc2l6ZT0yKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PWMoMCwwLjMpLGxpbmV0eXBlPSJkb3R0ZWQiLGNvbG91cj0iZGFyayByZWQiKSArCmdlb21fdmxpbmUoeGludGVyY2VwdD1jKDAsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikKCgpnZ3Bsb3QobWF0LGFlcyh4PWNvbW1vbl9FbmdHZXJtLHk9Y29tbW9uX0l0YUF1cyxsYWJlbD1jb21wYXJlLGNvbG91cj1ncm91cCkpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUsc2l6ZT0wLjgpICsgZ2VvbV90ZXh0KHNpemU9MikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD1jKDAsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikgKwpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YygwLDAuMyksbGluZXR5cGU9ImRvdHRlZCIsY29sb3VyPSJkYXJrIHJlZCIpCgpnZ3Bsb3QobWF0LGFlcyh4PWNvbW1vbl9FbmdHZXJtLHk9Y29tbW9uX0VuZ0l0YSxsYWJlbD1jb21wYXJlLGNvbG91cj1ncm91cCkpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUsc2l6ZT0wLjgpICsgZ2VvbV90ZXh0KHNpemU9MikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD1jKDAsMC4zKSxsaW5ldHlwZT0iZG90dGVkIixjb2xvdXI9ImRhcmsgcmVkIikgKwpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YygwLDAuMyksbGluZXR5cGU9ImRvdHRlZCIsY29sb3VyPSJkYXJrIHJlZCIpCgpgYGAKCgoKIyBFdmFsdWF0ZSBpbnRlcm5hbCBjb25zaXN0ZW5jeSBvZiBrbm93biBjb25zdHJ1Y3RzIHdpdGggYWxwaGEKCmBgYHtyfQpzZXRzIDwtIGxpc3QoaWQudmFyPWxpa2VydF92YXJpYWJsZXMxW2dyZXAoIlxcLmlkMSQiLGxpa2VydF92YXJpYWJsZXMxKV0sCiAgICAgICAgICAgICBvdWdodC52YXI9bGlrZXJ0X3ZhcmlhYmxlczFbZ3JlcCgiXFwub3VnaHQxJCIsbGlrZXJ0X3ZhcmlhYmxlczEpXSwKICAgICAgICAgICAgIGludHIudmFyPWxpa2VydF92YXJpYWJsZXMxW2dyZXAoIlxcLmludHIxJCIsbGlrZXJ0X3ZhcmlhYmxlczEpXSwKICAgICAgICAgICAgIGluc3RydS52YXI9bGlrZXJ0X3ZhcmlhYmxlczFbZ3JlcCgiXFwuaW5zdHJ1MSQiLGxpa2VydF92YXJpYWJsZXMxKV0sCiAgICAgICAgICAgICBpbnRlZ3IxLnZhcj1saWtlcnRfdmFyaWFibGVzMVtncmVwKCJcXC5pbnRlZ3IxJCIsbGlrZXJ0X3ZhcmlhYmxlczEpXSwKICAgICAgICAgICAgIHByb2YudmFyPWxpa2VydF92YXJpYWJsZXMxW2dyZXAoIlxcLnByb2YxJCIsbGlrZXJ0X3ZhcmlhYmxlczEpXSwKICAgICAgICAgICAgIHBvc3QudmFyPWxpa2VydF92YXJpYWJsZXMxW2dyZXAoIlxcLnBvc3QxJCIsbGlrZXJ0X3ZhcmlhYmxlczEpXSwKICAgICAgICAgICAgIGNvbW0udmFyPWxpa2VydF92YXJpYWJsZXMxW2dyZXAoIlxcLmNvbW0xJCIsbGlrZXJ0X3ZhcmlhYmxlczEpXSkKICAgICAgICAgICAgICAKCmdldF9hbHBoYSA8LSBmdW5jdGlvbihkYXRhTW90LAogICAgICAgICAgICAgICAgICAgICAgdmFyPXNldHMkaWQudmFyKXsKICB2YXJfYWxwaGEgPC0gYWxwaGEoZGF0YU1vdFssdmFyXSkKICBkYXRhZiA8LSBkYXRhLmZyYW1lKGFscGhhPXZhcl9hbHBoYSR0b3RhbCwKICAgICAgICAgICAgICAgICAgICBkcm9wID0gdmFyX2FscGhhJGFscGhhLmRyb3ApCiAgcm93bmFtZXMoZGF0YWYpIDwtIHJvd25hbWVzKHZhcl9hbHBoYSRhbHBoYS5kcm9wKQogIHJldHVybihkYXRhZikKfQoKIyAiSXRhbGlhbiBpbiBBdXN0cmFsaWEiCml0YV9pbl9hdSA8LSBkby5jYWxsKHJiaW5kLGxhcHBseShzZXRzLGZ1bmN0aW9uKHgpIHsKICBnZXRfYWxwaGEoZGF0YT1maWx0ZXJlZF9jb252W2ZpbHRlcmVkX2NvbnYkQ29udGV4dCA9PSAiSXRhbGlhbiBpbiBBdXN0cmFsaWEiLF0sCiAgICAgICAgICAgICAgICAgICAgICB2YXI9eCl9KSkKaXRhX2luX2F1JHZhciA8LSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoaXRhX2luX2F1KSxzcGxpdD0iXFwuIiksZnVuY3Rpb24oeCkgeFsxXSkgCml0YV9pbl9hdSR2YXIuZnVsbCA8LSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoaXRhX2luX2F1KSxzcGxpdD0iXFwuIiksZnVuY3Rpb24oeCkgeFszXSkgCml0YV9pbl9hdSRDb250ZXh0IDwtICJJdGFsaWFuIGluIEF1c3RyYWxpYSIKcm93bmFtZXMoaXRhX2luX2F1KSA8LSBOVUxMCgojICJHZXJtYW4gaW4gQXVzdHJhbGlhIgpnZXJtX2luX2F1IDwtIGRvLmNhbGwocmJpbmQsbGFwcGx5KHNldHMsZnVuY3Rpb24oeCkgewogIGdldF9hbHBoYShkYXRhPWZpbHRlcmVkX2NvbnZbZmlsdGVyZWRfY29udiRDb250ZXh0ID09ICJHZXJtYW4gaW4gQXVzdHJhbGlhIixdLAogICAgICAgICAgICAgICAgICAgICAgdmFyPXgpfSkpCmdlcm1faW5fYXUkdmFyIDwtIHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhnZXJtX2luX2F1KSxzcGxpdD0iXFwuIiksZnVuY3Rpb24oeCkgeFsxXSkgCmdlcm1faW5fYXUkdmFyLmZ1bGwgPC0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGdlcm1faW5fYXUpLHNwbGl0PSJcXC4iKSxmdW5jdGlvbih4KSB4WzNdKSAKZ2VybV9pbl9hdSRDb250ZXh0IDwtICJHZXJtYW4gaW4gQXVzdHJhbGlhIgpyb3duYW1lcyhnZXJtX2luX2F1KSA8LSBOVUxMCgojICJFbmdsaXNoIGluIEdlcm1hbnkiCmVuZ19pbl9nZXJtIDwtIGRvLmNhbGwocmJpbmQsbGFwcGx5KHNldHNbIShuYW1lcyhzZXRzKSAlaW4lICJjb21tLnZhciIpXSxmdW5jdGlvbih4KSB7CiAgZ2V0X2FscGhhKGRhdGE9ZmlsdGVyZWRfY29udltmaWx0ZXJlZF9jb252JENvbnRleHQgPT0gIkVuZ2xpc2ggaW4gR2VybWFueSIsXSwKICAgICAgICAgICAgICAgICAgICAgIHZhcj14KX0pKQoKIyB0aGUgb25lcyB0aGF0IG1ha2VzIGlzc3VlcwpnZXRfYWxwaGEoZGF0YT1maWx0ZXJlZF9jb252W2ZpbHRlcmVkX2NvbnYkQ29udGV4dCA9PSAiRW5nbGlzaCBpbiBHZXJtYW55IixdLAogICAgICAgICAgICAgICAgICAgICAgdmFyPXNldHMkb3VnaHQudmFyKQoKZW5nX2luX2dlcm0kdmFyIDwtIHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhlbmdfaW5fZ2VybSksc3BsaXQ9IlxcLiIpLGZ1bmN0aW9uKHgpIHhbMV0pIAplbmdfaW5fZ2VybSR2YXIuZnVsbCA8LSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoZW5nX2luX2dlcm0pLHNwbGl0PSJcXC4iKSxmdW5jdGlvbih4KSB4WzNdKSAKZW5nX2luX2dlcm0kQ29udGV4dCA8LSAiRW5nbGlzaCBpbiBHZXJtYW55Igpyb3duYW1lcyhlbmdfaW5fZ2VybSkgPC0gTlVMTAoKIyAiRW5nbGlzaCBpbiBJdGFseSIKZW5nX2luX2l0YSA8LSBkby5jYWxsKHJiaW5kLGxhcHBseShzZXRzWyEobmFtZXMoc2V0cykgJWluJSAiY29tbS52YXIiKV0sZnVuY3Rpb24oeCkgewogIGdldF9hbHBoYShkYXRhPWZpbHRlcmVkX2NvbnZbZmlsdGVyZWRfY29udiRDb250ZXh0ID09ICJFbmdsaXNoIGluIEl0YWx5IixdLAogICAgICAgICAgICAgICAgICAgICAgdmFyPXgpfSkpCmVuZ19pbl9pdGEkdmFyIDwtIHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhlbmdfaW5faXRhKSxzcGxpdD0iXFwuIiksZnVuY3Rpb24oeCkgeFsxXSkgCmVuZ19pbl9pdGEkdmFyLmZ1bGwgPC0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGVuZ19pbl9pdGEpLHNwbGl0PSJcXC4iKSxmdW5jdGlvbih4KSB4WzNdKSAKZW5nX2luX2l0YSRDb250ZXh0IDwtICJFbmdsaXNoIGluIEl0YWx5Igpyb3duYW1lcyhlbmdfaW5faXRhKSA8LSBOVUxMCgoKIyBjb21iaW5lCmZ1bGxfYWxwaGEgPC0gcmJpbmQoZW5nX2luX2l0YSxlbmdfaW5fZ2VybSxnZXJtX2luX2F1LGl0YV9pbl9hdSkKCmBgYAoKLSBQbG90IGFscGhhIGJ5IHZhcmlhYmxlCgpgYGB7ciBhbHBoYV9jaHJvbmJhY2hfYnlfY29udGV4dH0KCmZ1bGxfYWxwaGEgJT4lIGdyb3VwX2J5KENvbnRleHQsdmFyKSAlPiUgCiAgc3VtbWFyaXNlKHN0LmFscGhhID0gdW5pcXVlKGFscGhhLnN0ZC5hbHBoYSksCiAgICAgICAgICAgIEc2PXVuaXF1ZShhbHBoYS5HNi5zbWMuKSkgJT4lCiAgZ2dwbG90KC4sYWVzKHg9dmFyLHk9c3QuYWxwaGEsY29sb3VyPUNvbnRleHQpKSArIGdlb21fcG9pbnQoKSArIGdlb21fbGluZShhZXMoZ3JvdXA9Q29udGV4dCkpICsgdGhlbWVfYncoKQoKYGBgCgoKYGBge3IgZmlnLmhlaWdodD0xOCxmaWcud2lkdGg9MTR9CmFsbF9tZWx0IDwtIGFsbF9tZWx0ICU+JSBzZXBhcmF0ZSh2YXJpYWJsZSxpbnRvPWMoIml0ZW0iLCJ0eXBlIiksc2VwPSJcXC4iLHJlbW92ZT1GQUxTRSkKcDE9Z2dwbG90KGFsbF9tZWx0LGFlcyh4PXZhcmlhYmxlLGZpbGw9dmFsdWUpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIikgKyAKICBmYWNldF9ncmlkKENvbnRleHR+dHlwZSxzY2FsZXMgPSAiZnJlZSIpICsgZ2d0aXRsZSgiRmlsdGVyZWQgZGF0YXNldCIpK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSt0aGVtZV9idygpCgpwMj1nZ3Bsb3QoZnVsbF9hbHBoYSxhZXMoeD12YXIuZnVsbCx5PWRyb3Auc3RkLmFscGhhLGNvbG91cj1Db250ZXh0KSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX2xpbmUoYWVzKGdyb3VwPUNvbnRleHQpKSArIHRoZW1lX2J3KCkgKyBmYWNldF93cmFwKH52YXIsc2NhbGVzPSJmcmVlIikKCnA0PWdncGxvdChmdWxsX2FscGhhLGFlcyh4PXZhci5mdWxsLHk9ZHJvcC5hdmVyYWdlX3IsY29sb3VyPUNvbnRleHQpKSArIGdlb21fcG9pbnQoKSArIGdlb21fbGluZShhZXMoZ3JvdXA9Q29udGV4dCkpICsgdGhlbWVfYncoKSArIGZhY2V0X3dyYXAofnZhcixzY2FsZXM9ImZyZWUiKQoKcDM9ZnVsbF9hbHBoYSAlPiUgZ3JvdXBfYnkoQ29udGV4dCx2YXIpICU+JSAKICBzdW1tYXJpc2Uoc3QuYWxwaGEgPSB1bmlxdWUoYWxwaGEuc3RkLmFscGhhKSwKICAgICAgICAgICAgRzY9dW5pcXVlKGFscGhhLkc2LnNtYy4pKSAlPiUKICBnZ3Bsb3QoLixhZXMoeD12YXIseT1zdC5hbHBoYSxjb2xvdXI9Q29udGV4dCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9saW5lKGFlcyhncm91cD1Db250ZXh0KSkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyB0aGVtZV9idygpCgoKY293cGxvdDo6cGxvdF9ncmlkKHAyLHAzLG5yb3c9MikKCmBgYAoK